diff --git a/Applications/Diffusion/CMakeLists.txt b/Applications/Diffusion/CMakeLists.txt index c0bd44220d..c1f4e5175e 100644 --- a/Applications/Diffusion/CMakeLists.txt +++ b/Applications/Diffusion/CMakeLists.txt @@ -1,102 +1,97 @@ -if(MITK_USE_Python) - project(MitkDiffusion) set(DIFFUSIONAPP_NAME MitkDiffusion) set(_app_options) if(MITK_SHOW_CONSOLE_WINDOW) list(APPEND _app_options SHOW_CONSOLE) endif() # Create a cache entry for the provisioning file which is used to export # the file name in the MITKConfig.cmake file. This will keep external projects # which rely on this file happy. set(DIFFUSIONIMAGINGAPP_PROVISIONING_FILE "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${DIFFUSIONAPP_NAME}.provisioning" CACHE INTERNAL "${DIFFUSIONAPP_NAME} provisioning file" FORCE) # should be identical to the list in /CMake/mitkBuildConfigurationmitkDiffusion.cmake # remember to set plugins which should be automatically toggled in target_libraries.cmake set(_plugins org.commontk.configadmin org.commontk.eventadmin org.blueberry.core.runtime org.blueberry.core.expressions org.blueberry.core.commands org.blueberry.ui.qt org.blueberry.ui.qt.log org.blueberry.ui.qt.help org.mitk.core.services org.mitk.gui.common org.mitk.planarfigure org.mitk.core.ext org.mitk.gui.qt.application org.mitk.gui.qt.ext org.mitk.gui.qt.diffusionimagingapp org.mitk.gui.qt.common org.mitk.gui.qt.stdmultiwidgeteditor - org.mitk.gui.qt.common.legacy org.mitk.gui.qt.datamanager org.mitk.gui.qt.measurementtoolbox org.mitk.gui.qt.segmentation org.mitk.gui.qt.volumevisualization org.mitk.gui.qt.diffusionimaging org.mitk.gui.qt.diffusionimaging.connectomics org.mitk.gui.qt.diffusionimaging.fiberfox org.mitk.gui.qt.diffusionimaging.fiberprocessing org.mitk.gui.qt.diffusionimaging.ivim org.mitk.gui.qt.diffusionimaging.odfpeaks org.mitk.gui.qt.diffusionimaging.preprocessing org.mitk.gui.qt.diffusionimaging.reconstruction org.mitk.gui.qt.diffusionimaging.tractography org.mitk.gui.qt.diffusionimaging.registration org.mitk.gui.qt.diffusionimaging.denoising # org.mitk.gui.qt.matchpoint.algorithm.browser # org.mitk.gui.qt.matchpoint.algorithm.control # org.mitk.gui.qt.matchpoint.mapper org.mitk.gui.qt.imagenavigator org.mitk.gui.qt.moviemaker org.mitk.gui.qt.basicimageprocessing org.mitk.gui.qt.properties org.mitk.gui.qt.viewnavigator ) # Plug-ins listed below will not be # - added as a build-time dependency to the executable # - listed in the provisioning file for the executable # - installed if they are external plug-ins set(_exclude_plugins org.blueberry.test org.blueberry.uitest org.mitk.gui.qt.coreapplication org.mitk.gui.qt.extapplication ) set(_src_files MitkDiffusion.cpp ) qt5_add_resources(_src_files splashscreen.qrc) mitkFunctionCreateBlueBerryApplication( NAME ${DIFFUSIONAPP_NAME} DESCRIPTION "MITK Diffusion" PLUGINS ${_plugins} EXCLUDE_PLUGINS ${_exclude_plugins} SOURCES ${_src_files} ${_app_options} ) mitk_use_modules(TARGET ${DIFFUSIONAPP_NAME} MODULES MitkAppUtil) # Add meta dependencies (e.g. on auto-load modules from depending modules) if(TARGET ${CMAKE_PROJECT_NAME}-autoload) add_dependencies(${DIFFUSIONAPP_NAME} ${CMAKE_PROJECT_NAME}-autoload) endif() # Add a build time dependency to legacy BlueBerry bundles. if(MITK_MODULES_ENABLED_PLUGINS) add_dependencies(${DIFFUSIONAPP_NAME} ${MITK_MODULES_ENABLED_PLUGINS}) endif() - -endif() diff --git a/Applications/Diffusion/target_libraries.cmake b/Applications/Diffusion/target_libraries.cmake index 8688809ece..d9241ad619 100644 --- a/Applications/Diffusion/target_libraries.cmake +++ b/Applications/Diffusion/target_libraries.cmake @@ -1,34 +1,33 @@ # A list of plug-in targets which should be automatically enabled # (or be available in external projects) for this application set(target_libraries org_blueberry_ui_qt org_blueberry_ui_qt_help org_mitk_planarfigure org_mitk_gui_qt_diffusionimagingapp - org_mitk_gui_qt_common_legacy org_mitk_gui_qt_ext org_mitk_gui_qt_datamanager org_mitk_gui_qt_segmentation org_mitk_gui_qt_volumevisualization org_mitk_gui_qt_diffusionimaging org_mitk_gui_qt_diffusionimaging_connectomics org_mitk_gui_qt_diffusionimaging_fiberfox org_mitk_gui_qt_diffusionimaging_fiberprocessing org_mitk_gui_qt_diffusionimaging_ivim org_mitk_gui_qt_diffusionimaging_odfpeaks org_mitk_gui_qt_diffusionimaging_preprocessing org_mitk_gui_qt_diffusionimaging_reconstruction org_mitk_gui_qt_diffusionimaging_tractography org_mitk_gui_qt_diffusionimaging_registration org_mitk_gui_qt_diffusionimaging_denoising - org_mitk_gui_qt_matchpoint_algorithm_browser - org_mitk_gui_qt_matchpoint_algorithm_control - org_mitk_gui_qt_matchpoint_mapper +# org_mitk_gui_qt_matchpoint_algorithm_browser +# org_mitk_gui_qt_matchpoint_algorithm_control +# org_mitk_gui_qt_matchpoint_mapper org_mitk_gui_qt_imagenavigator org_mitk_gui_qt_moviemaker org_mitk_gui_qt_measurementtoolbox org_mitk_gui_qt_basicimageprocessing org_mitk_gui_qt_viewnavigator ) diff --git a/Applications/PluginGenerator/PluginTemplate/src/internal/QmitkTemplateView.cpp b/Applications/PluginGenerator/PluginTemplate/src/internal/QmitkTemplateView.cpp index 3a5a479ec1..e538a255ed 100644 --- a/Applications/PluginGenerator/PluginTemplate/src/internal/QmitkTemplateView.cpp +++ b/Applications/PluginGenerator/PluginTemplate/src/internal/QmitkTemplateView.cpp @@ -1,87 +1,87 @@ $(license) // Blueberry #include #include // Qmitk #include "$(view-file-name).h" // Qt #include // mitk image #include const std::string $(view-class-name)::VIEW_ID = "$(view-id)"; void $(view-class-name)::SetFocus() { m_Controls.buttonPerformImageProcessing->setFocus(); } void $(view-class-name)::CreateQtPartControl(QWidget *parent) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi(parent); - connect(m_Controls.buttonPerformImageProcessing, SIGNAL(clicked()), this, SLOT(DoImageProcessing())); + connect(m_Controls.buttonPerformImageProcessing, &QPushButton::clicked, this, &$(view-class-name)::DoImageProcessing); } void $(view-class-name)::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*source*/, const QList &nodes) { // iterate all selected objects, adjust warning visibility foreach (mitk::DataNode::Pointer node, nodes) { if (node.IsNotNull() && dynamic_cast(node->GetData())) { m_Controls.labelWarning->setVisible(false); m_Controls.buttonPerformImageProcessing->setEnabled(true); return; } } m_Controls.labelWarning->setVisible(true); m_Controls.buttonPerformImageProcessing->setEnabled(false); } void $(view-class-name)::DoImageProcessing() { QList nodes = this->GetDataManagerSelection(); if (nodes.empty()) return; mitk::DataNode *node = nodes.front(); if (!node) { // Nothing selected. Inform the user and return QMessageBox::information(nullptr, "Template", "Please load and select an image before starting image processing."); return; } // here we have a valid mitk::DataNode // a node itself is not very useful, we need its data item (the image) mitk::BaseData *data = node->GetData(); if (data) { // test if this data item is an image or not (could also be a surface or something totally different) mitk::Image *image = dynamic_cast(data); if (image) { std::stringstream message; std::string name; message << "Performing image processing for image "; if (node->GetName(name)) { // a property called "name" was found for this DataNode message << "'" << name << "'"; } message << "."; MITK_INFO << message.str(); // actually do something here... } } } diff --git a/Applications/PluginGenerator/PluginTemplate/src/internal/QmitkTemplateView.h b/Applications/PluginGenerator/PluginTemplate/src/internal/QmitkTemplateView.h index 4dfc824c98..7009ec6c2e 100644 --- a/Applications/PluginGenerator/PluginTemplate/src/internal/QmitkTemplateView.h +++ b/Applications/PluginGenerator/PluginTemplate/src/internal/QmitkTemplateView.h @@ -1,46 +1,44 @@ $(license) #ifndef $(view-file-name)_h #define $(view-file-name)_h #include #include #include "ui_$(view-file-name)Controls.h" /** \brief $(view-class-name) \warning This class is not yet documented. Use "git blame" and ask the author to provide basic documentation. \sa QmitkAbstractView \ingroup ${plugin_target}_internal */ class $(view-class-name) : public QmitkAbstractView { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: static const std::string VIEW_ID; -protected slots: - - /// \brief Called when the user clicks the GUI button - void DoImageProcessing(); - protected: virtual void CreateQtPartControl(QWidget *parent) override; virtual void SetFocus() override; /// \brief called by QmitkFunctionality when DataManager's selection has changed virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer source, const QList &nodes) override; + /// \brief Called when the user clicks the GUI button + void DoImageProcessing(); + Ui::$(view-file-name)Controls m_Controls; }; #endif // $(view-file-name)_h diff --git a/CMake/BuildConfigurations/DiffusionRelease.cmake b/CMake/BuildConfigurations/DiffusionRelease.cmake index 9c7164d6da..144f7174dd 100644 --- a/CMake/BuildConfigurations/DiffusionRelease.cmake +++ b/CMake/BuildConfigurations/DiffusionRelease.cmake @@ -1,40 +1,38 @@ message(STATUS "Configuring MITK Diffusion Release Build") # Enable non-optional external dependencies set(MITK_USE_Vigra ON CACHE BOOL "MITK Use Vigra Library" FORCE) set(MITK_USE_HDF5 ON CACHE BOOL "MITK Use HDF5 Library" FORCE) set(MITK_USE_MatchPoint ON CACHE BOOL "" FORCE) set(MITK_USE_DCMTK ON CACHE BOOL "" FORCE) set(MITK_USE_DCMQI ON CACHE BOOL "" FORCE) -set(MITK_USE_Python ON CACHE BOOL "" FORCE) -set(MITK_USE_SYSTEM_PYTHON ON CACHE BOOL "" FORCE) # Disable all apps but MITK Diffusion set(MITK_BUILD_ALL_APPS OFF CACHE BOOL "Build all MITK applications" FORCE) set(MITK_BUILD_APP_CoreApp OFF CACHE BOOL "Build the MITK CoreApp" FORCE) set(MITK_BUILD_APP_Workbench OFF CACHE BOOL "Build the MITK Workbench" FORCE) set(MITK_BUILD_APP_Diffusion ON CACHE BOOL "Build MITK Diffusion" FORCE) # Activate Diffusion Mini Apps set(BUILD_DiffusionCoreCmdApps OFF CACHE BOOL "Build commandline tools for diffusion" FORCE) set(BUILD_DiffusionFiberProcessingCmdApps ON CACHE BOOL "Build commandline tools for diffusion fiber processing" FORCE) set(BUILD_DiffusionFiberfoxCmdApps ON CACHE BOOL "Build commandline tools for diffusion data simulation (Fiberfox)" FORCE) set(BUILD_DiffusionMiscCmdApps OFF CACHE BOOL "Build miscellaneous commandline tools for diffusion" FORCE) set(BUILD_DiffusionQuantificationCmdApps OFF CACHE BOOL "Build commandline tools for diffusion quantification (IVIM, ADC, ...)" FORCE) set(BUILD_DiffusionTractographyCmdApps ON CACHE BOOL "Build commandline tools for diffusion fiber tractography" FORCE) set(BUILD_DiffusionTractographyEvaluationCmdApps OFF CACHE BOOL "Build commandline tools for diffusion fiber tractography evaluation" FORCE) set(BUILD_DiffusionConnectomicsCmdApps ON CACHE BOOL "Build commandline tools for diffusion connectomics" FORCE) # Build neither all plugins nor examples set(MITK_BUILD_ALL_PLUGINS OFF CACHE BOOL "Build all MITK plugins" FORCE) set(MITK_BUILD_EXAMPLES OFF CACHE BOOL "Build the MITK examples" FORCE) set(BUILD_TESTING OFF CACHE BOOL "Build the MITK tests" FORCE) # Activate in-application help generation set(MITK_DOXYGEN_GENERATE_QCH_FILES ON CACHE BOOL "Use doxygen to generate Qt compressed help files for MITK docs" FORCE) set(BLUEBERRY_USE_QT_HELP ON CACHE BOOL "Enable support for integrating bundle documentation into Qt Help" FORCE) # Enable console window set(MITK_SHOW_CONSOLE_WINDOW ON CACHE BOOL "Use this to enable or disable the console window when starting MITK GUI Applications" FORCE) set(CMAKE_BUILD_TYPE Release CACHE STRING "" FORCE) diff --git a/CMake/BuildConfigurations/camiPhotoacousticsWorkstation.cmake b/CMake/BuildConfigurations/camiPhotoacousticsWorkstation.cmake new file mode 100644 index 0000000000..14a6e49fd8 --- /dev/null +++ b/CMake/BuildConfigurations/camiPhotoacousticsWorkstation.cmake @@ -0,0 +1,21 @@ +message(STATUS "Configuring MITK Photoacoustics Setup Build") + +# 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) + +set(MITK_USE_OpenCL ON CACHE BOOL "MITK Use OpenCL 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.imagenavigator + org.mitk.gui.qt.properties + org.mitk.gui.qt.viewnavigator + org.mitk.gui.qt.ultrasound + org.mitk.gui.qt.photoacoustics.imageprocessing + org.mitk.gui.qt.measurementtoolbox + org.mitk.gui.qt.pointsetinteraction +) + diff --git a/CMake/FindOpenCL.cmake b/CMake/FindOpenCL.cmake index e30fb7a484..848594e9e3 100644 --- a/CMake/FindOpenCL.cmake +++ b/CMake/FindOpenCL.cmake @@ -1,89 +1,88 @@ # - Try to find OpenCL # This module tries to find an OpenCL implementation on your system. It supports # AMD / ATI, Apple and NVIDIA implementations, but should work, too. # # To set manually the paths, define these environment variables: # OpenCL_INCPATH - Include path (e.g. OpenCL_INCPATH=/opt/cuda/4.0/cuda/include) # OpenCL_LIBPATH - Library path (e.h. OpenCL_LIBPATH=/usr/lib64/nvidia) # # Once done this will define # OPENCL_FOUND - system has OpenCL # OPENCL_INCLUDE_DIRS - the OpenCL include directory # OPENCL_LIBRARIES - link these to use OpenCL # # WIN32 should work, but is untested FIND_PACKAGE(PackageHandleStandardArgs) SET (OPENCL_VERSION_STRING "0.1.0") SET(OPENCL_VERSION_MAJOR 0) SET(OPENCL_VERSION_MINOR 1) SET(OPENCL_VERSION_PATCH 0) IF(APPLE) FIND_LIBRARY(OPENCL_LIBRARIES OpenCL DOC "OpenCL lib for OSX") FIND_PATH(OPENCL_INCLUDE_DIRS OpenCL/cl.h DOC "Include for OpenCL on OSX") FIND_PATH(_OPENCL_CPP_INCLUDE_DIRS OpenCL/cl.hpp DOC "Include for OpenCL CPP bindings on OSX") ELSE() IF (WIN32) FIND_PATH(OPENCL_INCLUDE_DIRS CL/cl.h) FIND_PATH(_OPENCL_CPP_INCLUDE_DIRS CL/cl.hpp) IF(CMAKE_SIZEOF_VOID_P MATCHES "8") SET(OPENCL_LIB_DIR "$ENV{ATISTREAMSDKROOT}/lib/x86_64") if(NOT IS_DIRECTORY ${OPENCL_LIB_DIR}) SET(OPENCL_LIB_DIR "$ENV{CUDA_PATH}/lib/x64") endif() ELSE() SET(OPENCL_LIB_DIR "$ENV{ATISTREAMSDKROOT}/lib/x86") if(NOT IS_DIRECTORY ${OPENCL_LIB_DIR}) # need to convert path in the cmake style ? SET(OPENCL_LIB_DIR "$ENV{CUDA_PATH}/lib/Win32") endif() ENDIF() file(TO_CMAKE_PATH ${OPENCL_LIB_DIR} OPENCL_LIB_DIR) GET_FILENAME_COMPONENT(OPENCL_LIB_DIR ${OPENCL_LIB_DIR} ABSOLUTE) FIND_LIBRARY(OPENCL_LIBRARIES OpenCL.lib PATHS ${OPENCL_LIB_DIR} ENV OpenCL_LIBPATH) GET_FILENAME_COMPONENT(_OPENCL_INC_CAND ${OPENCL_LIB_DIR}/../../include ABSOLUTE) # On Win32 search relative to the library FIND_PATH(OPENCL_INCLUDE_DIRS CL/cl.h PATHS "${_OPENCL_INC_CAND}" ENV OpenCL_INCPATH) FIND_PATH(_OPENCL_CPP_INCLUDE_DIRS CL/cl.hpp PATHS "${_OPENCL_INC_CAND}" ENV OpenCL_INCPATH) - ELSE (WIN32) + ELSE () # Unix style platforms - FIND_LIBRARY(OPENCL_LIBRARIES OpenCL - PATHS ENV LD_LIBRARY_PATH ENV OpenCL_LIBPATH + FIND_LIBRARY(OPENCL_LIBRARIES libOpenCL.so + PATHS "/usr/local/cuda/lib64" "/opt/AMDAPP/lib64" ENV LD_LIBRARY_PATH ENV OpenCL_LIBPATH ) - GET_FILENAME_COMPONENT(OPENCL_LIB_DIR ${OPENCL_LIBRARIES} PATH) GET_FILENAME_COMPONENT(_OPENCL_INC_CAND ${OPENCL_LIB_DIR}/../../include ABSOLUTE) # The AMD SDK currently does not place its headers # in /usr/include, therefore also search relative # to the library FIND_PATH(OPENCL_INCLUDE_DIRS CL/cl.h PATHS ${_OPENCL_INC_CAND} "/usr/local/cuda/include" "/opt/AMDAPP/include" ENV OpenCL_INCPATH) FIND_PATH(_OPENCL_CPP_INCLUDE_DIRS CL/cl.hpp PATHS ${_OPENCL_INC_CAND} "/usr/local/cuda/include" "/opt/AMDAPP/include" ENV OpenCL_INCPATH) - ENDIF (WIN32) + ENDIF () -ENDIF (APPLE) +ENDIF () FIND_PACKAGE_HANDLE_STANDARD_ARGS(OpenCL DEFAULT_MSG OPENCL_LIBRARIES OPENCL_INCLUDE_DIRS) IF(_OPENCL_CPP_INCLUDE_DIRS) SET( OPENCL_HAS_CPP_BINDINGS TRUE ) LIST( APPEND OPENCL_INCLUDE_DIRS ${_OPENCL_CPP_INCLUDE_DIRS} ) # This is often the same, so clean up LIST( REMOVE_DUPLICATES OPENCL_INCLUDE_DIRS ) ENDIF(_OPENCL_CPP_INCLUDE_DIRS) MARK_AS_ADVANCED( OPENCL_INCLUDE_DIRS ) diff --git a/Documentation/Doxygen/2-UserManual/MITKPluginManualsList.dox b/Documentation/Doxygen/2-UserManual/MITKPluginManualsList.dox index 13d05fa1af..67ac20c7c5 100644 --- a/Documentation/Doxygen/2-UserManual/MITKPluginManualsList.dox +++ b/Documentation/Doxygen/2-UserManual/MITKPluginManualsList.dox @@ -1,67 +1,68 @@ /** \page PluginListPage MITK Plugin Manuals \section PluginListPageOverview Overview The plugins and bundles provide much of the extended functionality of MITK. Each encapsulates a solution to a problem and associated features. This way one can easily assemble the necessary capabilites for a workflow without adding a lot of bloat, by combining plugins as needed. The distinction between developer and end user use is for convenience only and mainly distinguishes which group a plugin is primarily aimed at. \section PluginListPageEndUserPluginList List of Plugins for End User Use \li \subpage org_blueberry_ui_qt_log \li \subpage org_mitk_views_basicimageprocessing \li \subpage org_mitk_views_cmdlinemodules \li \subpage org_mitk_views_datamanager \li \subpage org_mitk_gui_qt_dicom \li \subpage org_mitk_gui_qt_dicominspector \li \subpage org_mitk_gui_qt_diffusionimaging \li \subpage org_mitk_gui_qt_imagecropper \li \subpage org_mitk_views_imagenavigator \li \subpage org_mitk_gui_qt_measurementtoolbox \li \subpage org_mitk_gui_qt_moviemaker \li \subpage org_mitk_views_screenshotmaker + \li \subpage org_mitk_gui_qt_photoacoustics_imageprocessing \li \subpage org_mitk_views_pointsetinteraction \li \subpage org_mitk_gui_qt_pointsetinteractionmultispectrum \li \subpage org_mitk_gui_qt_python \li \subpage org_mitk_gui_qt_remeshing \li \subpage org_mitk_views_segmentation \li \subpage org_mitk_views_multilabelsegmentation \li \subpage org_mitk_gui_qt_spectrocamrecorder \li \subpage org_mitk_gui_qt_ultrasound \li \subpage org_mitk_gui_qt_viewnavigator \li \subpage org_mitk_views_volumevisualization \li \subpage org_mitk_gui_qt_xnat \li \subpage org_mitk_gui_qt_aicpregistration \li \subpage org_mitk_gui_qt_igtlplugin \li \subpage org_mitk_gui_qt_geometrytools \li \subpage org_mitk_gui_qt_classificationsegmentation \li \subpage org_mitk_gui_qt_matchpoint_algorithm_batch \li \subpage org_mitk_gui_qt_matchpoint_algorithm_browser \li \subpage org_mitk_gui_qt_matchpoint_algorithm_control \li \subpage org_mitk_gui_qt_matchpoint_evaluator \li \subpage org_mitk_gui_qt_matchpoint_framereg \li \subpage org_mitk_gui_qt_matchpoint_manipulator \li \subpage org_mitk_gui_qt_matchpoint_mapper \li \subpage org_mitk_gui_qt_matchpoint_visualizer \li \subpage org_mitk_gui_qt_cest \section PluginListPageDevPluginList List of Plugins for Developer Use and Examples \li \subpage org_surfacematerialeditor \li \subpage org_toftutorial \li \subpage org_mitk_gui_qt_examples \li \subpage org_mitkexamplesopencv \li \subpage org_mitk_gui_qt_igtexample \li \subpage org_mitk_gui_qt_igttracking \li \subpage org_mitk_gui_qt_igt_app_echotrack \li \subpage org_blueberry_ui_qt_objectinspector \li \subpage org_mitk_gui_qt_eventrecorder \li \subpage org_mitk_gui_qt_overlaymanager \li \subpage org_mitk_example_gui_pcaexample \li \subpage org_mitk_gui_qt_renderwindowmanager \li \subpage org_mitk_gui_qt_lasercontrol \li \subpage org_mitk_gui_qt_photoacoustics_imageprocessing \li \subpage org_mitk_gui_qt_lasercontrol \li \subpage org_mitk_gui_qt_igttrackingsemiautomaticmeasurement */ diff --git a/Documentation/Doxygen/3-DeveloperManual/Toolkit/ModuleManuals/MITKModuleManualsList.dox b/Documentation/Doxygen/3-DeveloperManual/Toolkit/ModuleManuals/MITKModuleManualsList.dox index 204dd984fd..3d18e0605d 100644 --- a/Documentation/Doxygen/3-DeveloperManual/Toolkit/ModuleManuals/MITKModuleManualsList.dox +++ b/Documentation/Doxygen/3-DeveloperManual/Toolkit/ModuleManuals/MITKModuleManualsList.dox @@ -1,30 +1,31 @@ /** \page MITKModuleManualsListPage MITK Module Manuals \section MITKModuleManualsListPageOverview Overview The modules are shared libraries that provide functionality that can be used by developers. \section MITKModuleManualsListPageModuleManualList List of Module Manuals \li \subpage NavigationGeneralModulePage \li \subpage MitkOpenCL_Overview \li \subpage LegacyGLModule \li \subpage GeneratingDeviceModulesPage \li \subpage mitkPython_Overview \li \subpage USModulePage + \li \subpage PAModulePage \li \subpage AnnotationModulePage \li \subpage ChartModule \section MITKModuleManualsListPageAdditionalInformation Additional Information on Certain Modules \li \ref PlanarPropertiesPage \li \subpage DiffusionImagingPropertiesPage \li \subpage ConnectomicsRenderingPropertiesPage \section MITKMigrationGuides Migration Guides \li \subpage InteractionMigration \li \subpage GeometryMigration \li \subpage OverlayMigration */ diff --git a/Modules/CEST/src/mitkCESTImageNormalizationFilter.cpp b/Modules/CEST/src/mitkCESTImageNormalizationFilter.cpp index ff084fb3d8..27281c892f 100644 --- a/Modules/CEST/src/mitkCESTImageNormalizationFilter.cpp +++ b/Modules/CEST/src/mitkCESTImageNormalizationFilter.cpp @@ -1,188 +1,195 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkCESTImageNormalizationFilter.h" #include #include #include #include #include mitk::CESTImageNormalizationFilter::CESTImageNormalizationFilter() { } mitk::CESTImageNormalizationFilter::~CESTImageNormalizationFilter() { } void mitk::CESTImageNormalizationFilter::GenerateData() { mitk::Image::ConstPointer inputImage = this->GetInput(0); if ((inputImage->GetDimension() != 4)) { mitkThrow() << "mitk::CESTImageNormalizationFilter:GenerateData works only with 4D images, sorry."; return; } auto resultMitkImage = this->GetOutput(); AccessFixedDimensionByItk(inputImage, NormalizeTimeSteps, 4); auto originalTimeGeometry = this->GetInput()->GetTimeGeometry(); auto resultTimeGeometry = mitk::ProportionalTimeGeometry::New(); unsigned int numberOfNonM0s = m_NonM0Indices.size(); resultTimeGeometry->Expand(numberOfNonM0s); for (unsigned int index = 0; index < numberOfNonM0s; ++index) { resultTimeGeometry->SetTimeStepGeometry(originalTimeGeometry->GetGeometryCloneForTimeStep(m_NonM0Indices.at(index)), index); } resultMitkImage->SetTimeGeometry(resultTimeGeometry); resultMitkImage->SetPropertyList(this->GetInput()->GetPropertyList()->Clone()); resultMitkImage->GetPropertyList()->SetStringProperty(mitk::CustomTagParser::m_OffsetsPropertyName.c_str(), m_RealOffsets.c_str()); // remove uids resultMitkImage->GetPropertyList()->DeleteProperty("DICOM.0008.0018"); resultMitkImage->GetPropertyList()->DeleteProperty("DICOM.0020.000D"); resultMitkImage->GetPropertyList()->DeleteProperty("DICOM.0020.000E"); } template void mitk::CESTImageNormalizationFilter::NormalizeTimeSteps(const itk::Image* image) { typedef itk::Image ImageType; typedef itk::Image OutputImageType; std::string offsets = ""; this->GetInput()->GetPropertyList()->GetStringProperty(mitk::CustomTagParser::m_OffsetsPropertyName.c_str(), offsets); std::vector parts; boost::split(parts, offsets, boost::is_any_of(" ")); // determine normalization images std::vector mZeroIndices; std::stringstream offsetsWithoutM0; m_NonM0Indices.clear(); for (unsigned int index = 0; index < parts.size(); ++index) { if ((std::stod(parts.at(index)) < -299) || (std::stod(parts.at(index)) > 299)) { mZeroIndices.push_back(index); } else { offsetsWithoutM0 << parts.at(index) << " "; m_NonM0Indices.push_back(index); } } auto resultImage = OutputImageType::New(); typename ImageType::RegionType targetEntireRegion = image->GetLargestPossibleRegion(); targetEntireRegion.SetSize(3, m_NonM0Indices.size()); resultImage->SetRegions(targetEntireRegion); resultImage->Allocate(); resultImage->FillBuffer(0); unsigned int numberOfTimesteps = image->GetLargestPossibleRegion().GetSize(3); typename ImageType::RegionType lowerMZeroRegion = image->GetLargestPossibleRegion(); lowerMZeroRegion.SetSize(3, 1); typename ImageType::RegionType upperMZeroRegion = image->GetLargestPossibleRegion(); upperMZeroRegion.SetSize(3, 1); typename ImageType::RegionType sourceRegion = image->GetLargestPossibleRegion(); sourceRegion.SetSize(3, 1); typename OutputImageType::RegionType targetRegion = resultImage->GetLargestPossibleRegion(); targetRegion.SetSize(3, 1); unsigned int targetTimestep = 0; for (unsigned int sourceTimestep = 0; sourceTimestep < numberOfTimesteps; ++sourceTimestep) { unsigned int lowerMZeroIndex = mZeroIndices[0]; unsigned int upperMZeroIndex = mZeroIndices[0]; for (unsigned int loop = 0; loop < mZeroIndices.size(); ++loop) { if (mZeroIndices[loop] <= sourceTimestep) { lowerMZeroIndex = mZeroIndices[loop]; } if (mZeroIndices[loop] > sourceTimestep) { upperMZeroIndex = mZeroIndices[loop]; break; } } bool isMZero = (lowerMZeroIndex == sourceTimestep); double weight = 0.0; if (lowerMZeroIndex == upperMZeroIndex) { weight = 1.0; } else { weight = 1.0 - double(sourceTimestep - lowerMZeroIndex) / double(upperMZeroIndex - lowerMZeroIndex); } if (isMZero) { //do nothing } else { lowerMZeroRegion.SetIndex(3, lowerMZeroIndex); upperMZeroRegion.SetIndex(3, upperMZeroIndex); sourceRegion.SetIndex(3, sourceTimestep); targetRegion.SetIndex(3, targetTimestep); itk::ImageRegionConstIterator lowerMZeroIterator(image, lowerMZeroRegion); itk::ImageRegionConstIterator upperMZeroIterator(image, upperMZeroRegion); itk::ImageRegionConstIterator sourceIterator(image, sourceRegion); itk::ImageRegionIterator targetIterator(resultImage.GetPointer(), targetRegion); while (!sourceIterator.IsAtEnd()) { - targetIterator.Set(double(sourceIterator.Get()) / - (weight * lowerMZeroIterator.Get() + (1.0 - weight) * upperMZeroIterator.Get())); + double normalizationFactor = weight * lowerMZeroIterator.Get() + (1.0 - weight) * upperMZeroIterator.Get(); + if (mitk::Equal(normalizationFactor, 0)) + { + targetIterator.Set(0); + } + else + { + targetIterator.Set(double(sourceIterator.Get()) / normalizationFactor); + } ++lowerMZeroIterator; ++upperMZeroIterator; ++sourceIterator; ++targetIterator; } ++targetTimestep; } } // get Pointer to output image mitk::Image::Pointer resultMitkImage = this->GetOutput(); // write into output image mitk::CastToMitkImage(resultImage, resultMitkImage); m_RealOffsets = offsetsWithoutM0.str(); } void mitk::CESTImageNormalizationFilter::GenerateOutputInformation() { mitk::Image::ConstPointer input = this->GetInput(); mitk::Image::Pointer output = this->GetOutput(); itkDebugMacro(<< "GenerateOutputInformation()"); } diff --git a/Modules/CommandLine/src/mitkCommandLineParser.cpp b/Modules/CommandLine/src/mitkCommandLineParser.cpp index b15a24e4b9..3e092e0ec7 100644 --- a/Modules/CommandLine/src/mitkCommandLineParser.cpp +++ b/Modules/CommandLine/src/mitkCommandLineParser.cpp @@ -1,957 +1,958 @@ /*=================================================================== 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. ===================================================================*/ /*========================================================================= Library: CTK Copyright (c) Kitware Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.txt Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =========================================================================*/ // STL includes #include #include // MITK includes #include "mitkCommandLineParser.h" using namespace std; namespace { // -------------------------------------------------------------------------- class CommandLineParserArgumentDescription { public: CommandLineParserArgumentDescription(const string &longArg, const string &longArgPrefix, const string &shortArg, const string &shortArgPrefix, mitkCommandLineParser::Type type, const string &argHelp, const string &argLabel, const us::Any &defaultValue, bool ignoreRest, bool deprecated, bool optional, string &argGroup, string &groupDescription) : LongArg(longArg), LongArgPrefix(longArgPrefix), ShortArg(shortArg), ShortArgPrefix(shortArgPrefix), ArgHelp(argHelp), ArgLabel(argLabel), ArgGroup(argGroup), ArgGroupDescription(groupDescription), IgnoreRest(ignoreRest), NumberOfParametersToProcess(0), Deprecated(deprecated), Optional(optional), DefaultValue(defaultValue), Value(type), ValueType(type) { Value = defaultValue; switch (type) { case mitkCommandLineParser::String: { NumberOfParametersToProcess = 1; } break; case mitkCommandLineParser::Bool: { NumberOfParametersToProcess = 0; } break; case mitkCommandLineParser::StringList: { NumberOfParametersToProcess = -1; } break; case mitkCommandLineParser::Int: { NumberOfParametersToProcess = 1; } break; case mitkCommandLineParser::Float: { NumberOfParametersToProcess = 1; } break; case mitkCommandLineParser::OutputDirectory: case mitkCommandLineParser::InputDirectory: { NumberOfParametersToProcess = 1; } break; case mitkCommandLineParser::OutputFile: case mitkCommandLineParser::InputFile: { NumberOfParametersToProcess = 1; } break; case mitkCommandLineParser::InputImage: { NumberOfParametersToProcess = 1; } break; default: std::cout << "Type not supported: " << static_cast(type); } } ~CommandLineParserArgumentDescription() {} bool addParameter(const string &value); string helpText(); string LongArg; string LongArgPrefix; string ShortArg; string ShortArgPrefix; string ArgHelp; string ArgLabel; string ArgGroup; string ArgGroupDescription; bool IgnoreRest; int NumberOfParametersToProcess; bool Deprecated; bool Optional; us::Any DefaultValue; us::Any Value; mitkCommandLineParser::Type ValueType; }; // -------------------------------------------------------------------------- bool CommandLineParserArgumentDescription::addParameter(const string &value) { switch (ValueType) { case mitkCommandLineParser::String: { Value = value; } break; case mitkCommandLineParser::Bool: { if (value.compare("true") == 0) Value = true; else Value = false; } break; case mitkCommandLineParser::StringList: { try { mitkCommandLineParser::StringContainerType list = us::any_cast(Value); list.push_back(value); Value = list; } catch (...) { mitkCommandLineParser::StringContainerType list; list.push_back(value); Value = list; } } break; case mitkCommandLineParser::Int: { stringstream ss(value); int i; ss >> i; Value = i; } break; case mitkCommandLineParser::Float: { stringstream ss(value); float f; ss >> f; Value = f; } break; case mitkCommandLineParser::InputDirectory: case mitkCommandLineParser::OutputDirectory: { Value = value; } break; case mitkCommandLineParser::InputFile: case mitkCommandLineParser::InputImage: case mitkCommandLineParser::OutputFile: { Value = value; } break; default: return false; } return true; } // -------------------------------------------------------------------------- string CommandLineParserArgumentDescription::helpText() { string text; string shortAndLongArg; if (!this->ShortArg.empty()) { shortAndLongArg = " "; shortAndLongArg += this->ShortArgPrefix; shortAndLongArg += this->ShortArg; } if (!this->LongArg.empty()) { if (this->ShortArg.empty()) shortAndLongArg.append(" "); else shortAndLongArg.append(", "); shortAndLongArg += this->LongArgPrefix; shortAndLongArg += this->LongArg; } text = text + shortAndLongArg + ", " + this->ArgHelp; if (this->Optional) text += " (optional)"; if (!this->DefaultValue.Empty()) { text = text + ", (default: " + this->DefaultValue.ToString() + ")"; } text += "\n"; return text; } } // -------------------------------------------------------------------------- // ctkCommandLineParser::ctkInternal class // -------------------------------------------------------------------------- class mitkCommandLineParser::ctkInternal { public: ctkInternal() : Debug(false), FieldWidth(0), StrictMode(false) {} ~ctkInternal() {} CommandLineParserArgumentDescription *argumentDescription(const string &argument); vector ArgumentDescriptionList; map ArgNameToArgumentDescriptionMap; map> GroupToArgumentDescriptionListMap; StringContainerType UnparsedArguments; StringContainerType ProcessedArguments; string ErrorString; bool Debug; string::size_type FieldWidth; string LongPrefix; string ShortPrefix; string CurrentGroup; string DisableQSettingsLongArg; string DisableQSettingsShortArg; bool StrictMode; }; // -------------------------------------------------------------------------- // ctkCommandLineParser::ctkInternal methods // -------------------------------------------------------------------------- CommandLineParserArgumentDescription *mitkCommandLineParser::ctkInternal::argumentDescription(const string &argument) { string unprefixedArg = argument; if (!LongPrefix.empty() && argument.compare(0, LongPrefix.size(), LongPrefix) == 0) { // Case when (ShortPrefix + UnPrefixedArgument) matches LongPrefix if (argument == LongPrefix && !ShortPrefix.empty() && argument.compare(0, ShortPrefix.size(), ShortPrefix) == 0) { unprefixedArg = argument.substr(ShortPrefix.size(), argument.size()); } else { unprefixedArg = argument.substr(LongPrefix.size(), argument.size()); } } else if (!ShortPrefix.empty() && argument.compare(0, ShortPrefix.size(), ShortPrefix) == 0) { unprefixedArg = argument.substr(ShortPrefix.size(), argument.size()); } else if (!LongPrefix.empty() && !ShortPrefix.empty()) { return nullptr; } if (ArgNameToArgumentDescriptionMap.count(unprefixedArg)) { return this->ArgNameToArgumentDescriptionMap[unprefixedArg]; } return nullptr; } // -------------------------------------------------------------------------- // ctkCommandLineParser methods // -------------------------------------------------------------------------- mitkCommandLineParser::mitkCommandLineParser() { this->Internal = new ctkInternal(); this->Category = string(); this->Title = string(); this->Contributor = string(); this->Description = string(); this->ParameterGroupName = "Parameters"; this->ParameterGroupDescription = "Parameters"; } // -------------------------------------------------------------------------- mitkCommandLineParser::~mitkCommandLineParser() { delete this->Internal; } // -------------------------------------------------------------------------- map mitkCommandLineParser::parseArguments(const StringContainerType &arguments, bool *ok) { // Reset this->Internal->UnparsedArguments.clear(); this->Internal->ProcessedArguments.clear(); this->Internal->ErrorString.clear(); // foreach (CommandLineParserArgumentDescription* desc, this->Internal->ArgumentDescriptionList) for (unsigned int i = 0; i < Internal->ArgumentDescriptionList.size(); i++) { CommandLineParserArgumentDescription *desc = Internal->ArgumentDescriptionList.at(i); desc->Value = us::Any(desc->ValueType); if (!desc->DefaultValue.Empty()) { desc->Value = desc->DefaultValue; } } bool error = false; bool ignoreRest = false; CommandLineParserArgumentDescription *currentArgDesc = nullptr; vector parsedArgDescriptions; for (unsigned int i = 1; i < arguments.size(); ++i) { string argument = arguments.at(i); if (this->Internal->Debug) { std::cout << "Processing" << argument; } if (!argument.compare("--xml") || !argument.compare("-xml") || !argument.compare("--XML") || !argument.compare("-XML")) { this->generateXmlOutput(); return map(); } // should argument be ignored ? if (ignoreRest) { if (this->Internal->Debug) { std::cout << " Skipping: IgnoreRest flag was been set"; } this->Internal->UnparsedArguments.push_back(argument); continue; } // Skip if the argument does not start with the defined prefix if (!(argument.compare(0, Internal->LongPrefix.size(), Internal->LongPrefix) == 0 || argument.compare(0, Internal->ShortPrefix.size(), Internal->ShortPrefix) == 0)) { if (this->Internal->StrictMode) { this->Internal->ErrorString = "Unknown argument "; this->Internal->ErrorString += argument; error = true; break; } if (this->Internal->Debug) { std::cout << " Skipping: It does not start with the defined prefix"; } this->Internal->UnparsedArguments.push_back(argument); continue; } // Skip if argument has already been parsed ... bool alreadyProcessed = false; for (auto alreadyHandledArgument : Internal->ProcessedArguments) if (argument.compare(alreadyHandledArgument) == 0) { alreadyProcessed = true; break; } if (alreadyProcessed) { if (this->Internal->StrictMode) { this->Internal->ErrorString = "Argument "; this->Internal->ErrorString += argument; this->Internal->ErrorString += " already processed !"; error = true; break; } if (this->Internal->Debug) { std::cout << " Skipping: Already processed !"; } continue; } // Retrieve corresponding argument description currentArgDesc = this->Internal->argumentDescription(argument); // Is there a corresponding argument description ? if (currentArgDesc) { // If the argument is deprecated, print the help text but continue processing if (currentArgDesc->Deprecated) { std::cout << "Deprecated argument " << argument << ": " << currentArgDesc->ArgHelp; } else { parsedArgDescriptions.push_back(currentArgDesc); } this->Internal->ProcessedArguments.push_back(currentArgDesc->ShortArg); this->Internal->ProcessedArguments.push_back(currentArgDesc->LongArg); int numberOfParametersToProcess = currentArgDesc->NumberOfParametersToProcess; ignoreRest = currentArgDesc->IgnoreRest; if (this->Internal->Debug && ignoreRest) { std::cout << " IgnoreRest flag is True"; } // Is the number of parameters associated with the argument being processed known ? if (numberOfParametersToProcess == 0) { currentArgDesc->addParameter("true"); } else if (numberOfParametersToProcess > 0) { string missingParameterError = "Argument %1 has %2 value(s) associated whereas exacly %3 are expected."; for (int j = 1; j <= numberOfParametersToProcess; ++j) { if (i + j >= arguments.size()) { // this->Internal->ErrorString = // missingParameterError.arg(argument).arg(j-1).arg(numberOfParametersToProcess); // if (this->Internal->Debug) { std::cout << this->Internal->ErrorString; } if (ok) { *ok = false; } return map(); } string parameter = arguments.at(i + j); if (this->Internal->Debug) { std::cout << " Processing parameter" << j << ", value:" << parameter; } if (this->argumentAdded(parameter)) { // this->Internal->ErrorString = // missingParameterError.arg(argument).arg(j-1).arg(numberOfParametersToProcess); // if (this->Internal->Debug) { std::cout << this->Internal->ErrorString; } if (ok) { *ok = false; } return map(); } if (!currentArgDesc->addParameter(parameter)) { // this->Internal->ErrorString = string( // "Value(s) associated with argument %1 are incorrect. %2"). // arg(argument).arg(currentArgDesc->ExactMatchFailedMessage); // if (this->Internal->Debug) { std::cout << this->Internal->ErrorString; } if (ok) { *ok = false; } return map(); } } // Update main loop increment i = i + numberOfParametersToProcess; } else if (numberOfParametersToProcess == -1) { if (this->Internal->Debug) { std::cout << " Proccessing StringList ..."; } int j = 1; while (j + i < arguments.size()) { if (this->argumentAdded(arguments.at(j + i))) { if (this->Internal->Debug) { std::cout << " No more parameter for" << argument; } break; } string parameter = arguments.at(j + i); if (parameter.compare(0, Internal->LongPrefix.size(), Internal->LongPrefix) == 0 || parameter.compare(0, Internal->ShortPrefix.size(), Internal->ShortPrefix) == 0) { j--; break; } if (this->Internal->Debug) { std::cout << " Processing parameter" << j << ", value:" << parameter; } if (!currentArgDesc->addParameter(parameter)) { // this->Internal->ErrorString = string( // "Value(s) associated with argument %1 are incorrect. %2"). // arg(argument).arg(currentArgDesc->ExactMatchFailedMessage); // if (this->Internal->Debug) { std::cout << this->Internal->ErrorString; } if (ok) { *ok = false; } return map(); } j++; } // Update main loop increment i = i + j; } } else { if (this->Internal->StrictMode) { this->Internal->ErrorString = "Unknown argument "; this->Internal->ErrorString += argument; error = true; break; } if (this->Internal->Debug) { std::cout << " Skipping: Unknown argument"; } this->Internal->UnparsedArguments.push_back(argument); } } if (ok) { *ok = !error; } map parsedArguments; int obligatoryArgs = 0; vector::iterator it; for (it = Internal->ArgumentDescriptionList.begin(); it != Internal->ArgumentDescriptionList.end(); ++it) { CommandLineParserArgumentDescription *desc = *it; if (!desc->Optional) obligatoryArgs++; } int parsedObligatoryArgs = 0; for (it = parsedArgDescriptions.begin(); it != parsedArgDescriptions.end(); ++it) { CommandLineParserArgumentDescription *desc = *it; string key; if (!desc->LongArg.empty()) { key = desc->LongArg; } else { key = desc->ShortArg; } if (!desc->Optional) parsedObligatoryArgs++; std::pair elem; elem.first = key; elem.second = desc->Value; parsedArguments.insert(elem); } if (obligatoryArgs > parsedObligatoryArgs) { parsedArguments.clear(); cout << helpText(); } return parsedArguments; } // ------------------------------------------------------------------------- map mitkCommandLineParser::parseArguments(int argc, char **argv, bool *ok) { + std::cout << "Running Command Line Utility *" << Title << "*" << std::endl; StringContainerType arguments; // Create a StringContainerType of arguments for (int i = 0; i < argc; ++i) arguments.push_back(argv[i]); return this->parseArguments(arguments, ok); } // ------------------------------------------------------------------------- string mitkCommandLineParser::errorString() const { return this->Internal->ErrorString; } // ------------------------------------------------------------------------- const mitkCommandLineParser::StringContainerType &mitkCommandLineParser::unparsedArguments() const { return this->Internal->UnparsedArguments; } // -------------------------------------------------------------------------- void mitkCommandLineParser::addArgument(const string &longarg, const string &shortarg, Type type, const string &argLabel, const string &argHelp, const us::Any &defaultValue, bool optional, bool ignoreRest, bool deprecated) { if (longarg.empty() && shortarg.empty()) { return; } /* Make sure it's not already added */ bool added = (this->Internal->ArgNameToArgumentDescriptionMap.count(longarg) != 0); if (added) { return; } added = (this->Internal->ArgNameToArgumentDescriptionMap.count(shortarg) != 0); if (added) { return; } auto argDesc = new CommandLineParserArgumentDescription(longarg, this->Internal->LongPrefix, shortarg, this->Internal->ShortPrefix, type, argHelp, argLabel, defaultValue, ignoreRest, deprecated, optional, ParameterGroupName, ParameterGroupDescription); std::string::size_type argWidth = 0; if (!longarg.empty()) { this->Internal->ArgNameToArgumentDescriptionMap[longarg] = argDesc; argWidth += longarg.size() + this->Internal->LongPrefix.size(); } if (!shortarg.empty()) { this->Internal->ArgNameToArgumentDescriptionMap[shortarg] = argDesc; argWidth += shortarg.size() + this->Internal->ShortPrefix.size() + 2; } argWidth += 5; // Set the field width for the arguments if (argWidth > this->Internal->FieldWidth) { this->Internal->FieldWidth = argWidth; } this->Internal->ArgumentDescriptionList.push_back(argDesc); this->Internal->GroupToArgumentDescriptionListMap[this->Internal->CurrentGroup].push_back(argDesc); } // -------------------------------------------------------------------------- void mitkCommandLineParser::addDeprecatedArgument(const string &longarg, const string &shortarg, const string &argLabel, const string &argHelp) { addArgument(longarg, shortarg, StringList, argLabel, argHelp, us::Any(), false, true, false); } // -------------------------------------------------------------------------- std::string::size_type mitkCommandLineParser::fieldWidth() const { return this->Internal->FieldWidth; } // -------------------------------------------------------------------------- void mitkCommandLineParser::beginGroup(const string &description) { this->Internal->CurrentGroup = description; } // -------------------------------------------------------------------------- void mitkCommandLineParser::endGroup() { this->Internal->CurrentGroup.clear(); } // -------------------------------------------------------------------------- string mitkCommandLineParser::helpText() const { string text; vector deprecatedArgs; text = "Command Line Utility *" + Title + "* in Category *" + Category + "*\n"; text += Description + "\n"; text += Contributor + "\n\n"; text += "Use --xml to generate an XML description parsable as a CTK Command Line Module Plugin.\n"; // Loop over grouped argument descriptions map>::iterator it; for (it = Internal->GroupToArgumentDescriptionListMap.begin(); it != Internal->GroupToArgumentDescriptionListMap.end(); ++it) { if (!(*it).first.empty()) { text = text + "\n" + (*it).first + "\n"; } vector::iterator it2; for (it2 = (*it).second.begin(); it2 != (*it).second.end(); ++it2) { CommandLineParserArgumentDescription *argDesc = *it2; if (argDesc->Deprecated) { deprecatedArgs.push_back(argDesc); } else { text += argDesc->helpText(); } } } if (!deprecatedArgs.empty()) { text += "\nDeprecated arguments:\n"; vector::iterator it2; for (it2 = deprecatedArgs.begin(); it2 != deprecatedArgs.end(); ++it2) { CommandLineParserArgumentDescription *argDesc = *it2; text += argDesc->helpText(); } } return text; } // -------------------------------------------------------------------------- bool mitkCommandLineParser::argumentAdded(const string &argument) const { return (this->Internal->ArgNameToArgumentDescriptionMap.count(argument) != 0); } // -------------------------------------------------------------------------- bool mitkCommandLineParser::argumentParsed(const string &argument) const { for (unsigned int i = 0; i < Internal->ProcessedArguments.size(); i++) if (argument.compare(Internal->ProcessedArguments.at(i)) == 0) return true; return false; } // -------------------------------------------------------------------------- void mitkCommandLineParser::setArgumentPrefix(const string &longPrefix, const string &shortPrefix) { this->Internal->LongPrefix = longPrefix; this->Internal->ShortPrefix = shortPrefix; } // -------------------------------------------------------------------------- void mitkCommandLineParser::setStrictModeEnabled(bool strictMode) { this->Internal->StrictMode = strictMode; } void mitkCommandLineParser::generateXmlOutput() { std::stringstream xml; xml << "" << endl; xml << "" << Category << "" << endl; xml << "" << Title << "" << endl; xml << "" << Description << "" << endl; xml << "" << Contributor << "" << endl; xml << "" << endl; std::vector::iterator it; std::string lastParameterGroup = ""; for (it = this->Internal->ArgumentDescriptionList.begin(); it != this->Internal->ArgumentDescriptionList.end(); it++) { std::string type; switch ((*it)->ValueType) { case mitkCommandLineParser::String: type = "string"; break; case mitkCommandLineParser::Bool: type = "boolean"; break; case mitkCommandLineParser::StringList: type = "string-vector"; break; case mitkCommandLineParser::Int: type = "integer"; break; case mitkCommandLineParser::Float: type = "float"; break; case mitkCommandLineParser::OutputDirectory: case mitkCommandLineParser::InputDirectory: type = "directory"; break; case mitkCommandLineParser::InputImage: type = "image"; break; case mitkCommandLineParser::OutputFile: case mitkCommandLineParser::InputFile: type = "file"; break; } if (lastParameterGroup.compare((*it)->ArgGroup)) { if (it != this->Internal->ArgumentDescriptionList.begin()) { xml << "" << endl; xml << "" << endl; } xml << "" << endl; xml << "" << (*it)->ArgGroupDescription << "" << endl; lastParameterGroup = (*it)->ArgGroup; } // Skip help item, as it's no use in GUI if ((*it)->ShortArg == "h") continue; xml << "<" << type << ">" << endl; xml << "" << (*it)->LongArg << "" << endl; xml << "" << (*it)->ArgHelp << "" << endl; xml << "" << endl; if (!(*it)->DefaultValue.Empty()) xml << "" << (*it)->DefaultValue.ToString() << "" << endl; xml << "" << (*it)->LongArg << "" << endl; xml << "" << (*it)->ShortArg << "" << endl; if ((*it)->ValueType == mitkCommandLineParser::InputDirectory || (*it)->ValueType == mitkCommandLineParser::InputFile || (*it)->ValueType == mitkCommandLineParser::InputImage) { xml << "input" << endl; } else if ((*it)->ValueType == mitkCommandLineParser::OutputDirectory || (*it)->ValueType == mitkCommandLineParser::OutputFile) { xml << "output" << endl; } xml << "" << endl; } xml << "" << endl; xml << "" << endl; cout << xml.str(); } void mitkCommandLineParser::setTitle(string title) { Title = title; } void mitkCommandLineParser::setContributor(string contributor) { Contributor = contributor; } void mitkCommandLineParser::setCategory(string category) { Category = category; } void mitkCommandLineParser::setDescription(string description) { Description = description; } void mitkCommandLineParser::changeParameterGroup(string name, string tooltip) { ParameterGroupName = name; ParameterGroupDescription = tooltip; } diff --git a/Modules/DiffusionImaging/DiffusionCore/include/Rendering/vtkOdfSource.h b/Modules/DiffusionImaging/DiffusionCore/include/Rendering/vtkOdfSource.h index 9efec48bef..dcc9b426eb 100644 --- a/Modules/DiffusionImaging/DiffusionCore/include/Rendering/vtkOdfSource.h +++ b/Modules/DiffusionImaging/DiffusionCore/include/Rendering/vtkOdfSource.h @@ -1,85 +1,85 @@ /*=================================================================== 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 __vtkOdfSource_h #define __vtkOdfSource_h #include #include "vtkPolyDataAlgorithm.h" #include "mitkCommon.h" #include #include #include class MITKDIFFUSIONCORE_EXPORT vtkOdfSource : public vtkPolyDataAlgorithm { public: vtkTypeMacro(vtkOdfSource,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent) override; typedef itk::OrientationDistributionFunction OdfType; // Description: // Construct sphere with radius=0.5 and default resolution 8 in both Phi // and Theta directions. Theta ranges from (0,360) and phi (0,180) degrees. static vtkOdfSource *New(); - vtkSetMacro(Scale,double); - vtkGetMacro(Scale,double); + vtkSetMacro(Scale,double) + vtkGetMacro(Scale,double) - vtkSetMacro(AdditionalScale,double); - vtkGetMacro(AdditionalScale,double); + vtkSetMacro(AdditionalScale,double) + vtkGetMacro(AdditionalScale,double) - vtkSetMacro(Normalization,int); - vtkGetMacro(Normalization,int); + vtkSetMacro(Normalization,int) + vtkGetMacro(Normalization,int) - vtkSetMacro(Odf,OdfType); - vtkGetMacro(Odf,OdfType); + vtkSetMacro(Odf,OdfType) + vtkGetMacro(Odf,OdfType) - vtkSetMacro(UseCustomColor,bool); - vtkGetMacro(UseCustomColor,bool); + vtkSetMacro(UseCustomColor,bool) + vtkGetMacro(UseCustomColor,bool) void SetColor(int r, int g, int b) { this->r = r; this->g = g; this->b = b; } protected: vtkOdfSource(); ~vtkOdfSource(); int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *) override; int RequestInformation(vtkInformation *, vtkInformationVector **, vtkInformationVector *) override; OdfType Odf; double Scale; double AdditionalScale; int Normalization; int r; int g; int b; bool UseCustomColor; vtkSmartPointer lut; private: vtkOdfSource(const vtkOdfSource&); // Not implemented. void operator=(const vtkOdfSource&); // Not implemented. }; #endif //__vtkOdfSource_h diff --git a/Modules/DiffusionImaging/DiffusionCore/src/Rendering/vtkOdfSource.cxx b/Modules/DiffusionImaging/DiffusionCore/src/Rendering/vtkOdfSource.cxx index 06090b9156..60a63733b5 100644 --- a/Modules/DiffusionImaging/DiffusionCore/src/Rendering/vtkOdfSource.cxx +++ b/Modules/DiffusionImaging/DiffusionCore/src/Rendering/vtkOdfSource.cxx @@ -1,133 +1,130 @@ #include "vtkOdfSource.h" #include "vtkCellArray.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkPoints.h" #include "vtkStreamingDemandDrivenPipeline.h" #include "vtkObjectFactory.h" #include "vtkDoubleArray.h" #include "vtkCellData.h" #include #include #include vtkStandardNewMacro(vtkOdfSource); vtkOdfSource::vtkOdfSource() : r(0) , g(0) , b(0) , UseCustomColor(false) { Scale = 1; - lut = vtkLookupTable::New(); + lut = vtkSmartPointer::New(); lut->SetRange(0,1); lut->Build(); this->SetNumberOfInputPorts(0); } vtkOdfSource::~vtkOdfSource() { - lut->Delete(); + } //---------------------------------------------------------------------------- int vtkOdfSource::RequestData( vtkInformation *vtkNotUsed(request), vtkInformationVector **vtkNotUsed(inputVector), vtkInformationVector *outputVector) { vtkPolyData* TemplateOdf = OdfType::GetBaseMesh(); // get the info object vtkInformation *outInfo = outputVector->GetInformationObject(0); // get the ouptut vtkPolyData *output = vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())); OdfType colorOdf; switch(Normalization) { case mitk::ODFN_MINMAX: Odf = Odf.MinMaxNormalize(); colorOdf = Odf; break; case mitk::ODFN_MAX: Odf = Odf.MaxNormalize(); colorOdf = Odf; break; case mitk::ODFN_NONE: colorOdf = Odf.MaxNormalize(); break; default: Odf = Odf.MaxNormalize(); colorOdf = Odf; } - vtkPoints *newPoints; vtkCellArray* polys = TemplateOdf->GetPolys(); output->SetPolys(polys); polys->InitTraversal(); - newPoints = vtkPoints::New(); + vtkSmartPointer newPoints = vtkSmartPointer::New(); int numPoints = TemplateOdf->GetPoints()->GetNumberOfPoints(); newPoints->Allocate(numPoints); vtkSmartPointer point_colors = vtkSmartPointer::New(); point_colors->Allocate(output->GetNumberOfPoints() * 4); point_colors->SetNumberOfComponents(4); point_colors->SetName("ODF_COLORS"); unsigned char rgba[4]; double rgb[3]; for(int j=0; jGetPoints()->GetPoint(j,p); double val = Odf.GetElement(j); p[0] *= val*Scale*AdditionalScale*0.5; p[1] *= val*Scale*AdditionalScale*0.5; p[2] *= val*Scale*AdditionalScale*0.5; newPoints->InsertNextPoint(p); if (UseCustomColor) { rgba[0] = (unsigned char)r; rgba[1] = (unsigned char)g; rgba[2] = (unsigned char)b; } else { double color_val = colorOdf.GetElement(j); lut->GetColor(1-color_val, rgb); rgba[0] = (unsigned char)(255.0*rgb[0]); rgba[1] = (unsigned char)(255.0*rgb[1]); rgba[2] = (unsigned char)(255.0*rgb[2]); } rgba[3] = 255; point_colors->InsertTypedTuple(j, rgba); } output->SetPoints(newPoints); output->GetPointData()->AddArray(point_colors); - newPoints->Delete(); - point_colors->Delete(); return 1; } //---------------------------------------------------------------------------- void vtkOdfSource::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } //---------------------------------------------------------------------------- int vtkOdfSource::RequestInformation( vtkInformation *vtkNotUsed(request), vtkInformationVector **vtkNotUsed(inputVector), vtkInformationVector *outputVector) { // get the info object vtkInformation *outInfo = outputVector->GetInformationObject(0); outInfo->Set(vtkAlgorithm::CAN_HANDLE_PIECE_REQUEST(),0); return 1; } diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractClusteringFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractClusteringFilter.cpp index d85f434205..c7feec9017 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractClusteringFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractClusteringFilter.cpp @@ -1,504 +1,492 @@ /*=================================================================== 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 "itkTractClusteringFilter.h" #define _USE_MATH_DEFINES #include #include #include namespace itk{ TractClusteringFilter::TractClusteringFilter() : m_NumPoints(12) , m_InCentroids(nullptr) , m_MinClusterSize(1) , m_MaxClusters(0) , m_MergeDuplicateThreshold(-1) , m_DoResampling(true) , m_FilterMask(nullptr) , m_OverlapThreshold(0.0) { } TractClusteringFilter::~TractClusteringFilter() { for (auto m : m_Metrics) delete m; } std::vector > TractClusteringFilter::GetOutFiberIndices() const { return m_OutFiberIndices; } void TractClusteringFilter::SetMetrics(const std::vector &Metrics) { m_Metrics = Metrics; } std::vector TractClusteringFilter::GetOutClusters() const { return m_OutClusters; } std::vector TractClusteringFilter::GetOutCentroids() const { return m_OutCentroids; } std::vector TractClusteringFilter::GetOutTractograms() const { return m_OutTractograms; } void TractClusteringFilter::SetDistances(const std::vector &Distances) { m_Distances = Distances; } float TractClusteringFilter::CalcOverlap(vnl_matrix& t) { float overlap = 0; if (m_FilterMask.IsNotNull()) { for (unsigned int i=0; i p = t.get_column(i); itk::Point point; point[0] = p[0]; point[1] = p[1]; point[2] = p[2]; itk::Index<3> idx; m_FilterMask->TransformPhysicalPointToIndex(point, idx); if (m_FilterMask->GetLargestPossibleRegion().IsInside(idx) && m_FilterMask->GetPixel(idx)>0) overlap += 1; } overlap /= m_NumPoints; } else return 1.0; return overlap; } std::vector > TractClusteringFilter::ResampleFibers(mitk::FiberBundle::Pointer tractogram) { mitk::FiberBundle::Pointer temp_fib = tractogram->GetDeepCopy(); if (m_DoResampling) temp_fib->ResampleToNumPoints(m_NumPoints); std::vector< vnl_matrix > out_fib; for (int i=0; iGetFiberPolyData()->GetNumberOfCells(); i++) { vtkCell* cell = temp_fib->GetFiberPolyData()->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vnl_matrix streamline; streamline.set_size(3, m_NumPoints); streamline.fill(0.0); for (int j=0; jGetPoint(j, cand); vnl_vector_fixed< float, 3 > candV; candV[0]=cand[0]; candV[1]=cand[1]; candV[2]=cand[2]; streamline.set_column(j, candV); } out_fib.push_back(streamline); } return out_fib; } std::vector< TractClusteringFilter::Cluster > TractClusteringFilter::ClusterStep(std::vector< long > f_indices, std::vector distances) { float dist_thres = distances.back(); distances.pop_back(); std::vector< Cluster > C; int N = f_indices.size(); Cluster c1; c1.I.push_back(f_indices.at(0)); c1.h = T[f_indices.at(0)]; c1.n = 1; C.push_back(c1); if (f_indices.size()==1) return C; for (int i=1; i t = T.at(f_indices.at(i)); int min_cluster_index = -1; float min_cluster_distance = 99999; bool flip = false; for (unsigned int k=0; k v = C.at(k).h / C.at(k).n; bool f = false; float d = 0; for (auto m : m_Metrics) d += m->CalculateDistance(t, v, f); d /= m_Metrics.size(); if (d=0 && min_cluster_distance outC; -#pragma omp parallel for +//#pragma omp parallel for for (int c=0; c<(int)C.size(); c++) { std::vector< Cluster > tempC = ClusterStep(C.at(c).I, distances); AppendCluster(outC, tempC); } return outC; } else return C; } void TractClusteringFilter::AppendCluster(std::vector< Cluster >& a, std::vector< Cluster >&b) { for (auto c : b) a.push_back(c); } void TractClusteringFilter::MergeDuplicateClusters(std::vector< TractClusteringFilter::Cluster >& clusters) { if (m_MergeDuplicateThreshold<0) m_MergeDuplicateThreshold = m_Distances.at(0)/2; bool found = true; MITK_INFO << "Merging duplicate clusters with distance threshold " << m_MergeDuplicateThreshold; int start = 0; while (found && m_MergeDuplicateThreshold>mitk::eps) { std::cout << " \r"; std::cout << "Number of clusters: " << clusters.size() << '\r'; cout.flush(); found = false; for (int k1=start; k1<(int)clusters.size(); ++k1) { Cluster c1 = clusters.at(k1); vnl_matrix t = c1.h / c1.n; std::vector< int > merge_indices; std::vector< bool > flip_indices; #pragma omp parallel for for (int k2=0; k2<(int)clusters.size(); ++k2) { if (k1!=k2) { Cluster c2 = clusters.at(k2); vnl_matrix v = c2.h / c2.n; bool f = false; -// d = m_Metric->CalculateDistance(t, v, f); // alwayse use MDF? float d = 0; for (auto m : m_Metrics) d += m->CalculateDistance(t, v, f); d /= m_Metrics.size(); #pragma omp critical if (d TractClusteringFilter::AddToKnownClusters(std::vector< long > f_indices, std::vector >& centroids) { float dist_thres = m_Distances.at(0); int N = f_indices.size(); std::vector< Cluster > C; vnl_matrix zero_h; zero_h.set_size(T.at(0).rows(), T.at(0).cols()); zero_h.fill(0.0); Cluster no_fit; no_fit.h = zero_h; for (unsigned int i=0; i t = T.at(f_indices.at(i)); int min_cluster_index = -1; float min_cluster_distance = 99999; bool flip = false; if (CalcOverlap(t)>=m_OverlapThreshold) { int c_idx = 0; for (vnl_matrix centroid : centroids) { bool f = false; float d = 0; for (auto m : m_Metrics) d += m->CalculateDistance(t, centroid, f); d /= m_Metrics.size(); if (d=0 && min_cluster_distance f_indices; for (unsigned int i=0; i clusters; if (m_InCentroids.IsNull()) { MITK_INFO << "Clustering fibers"; clusters = ClusterStep(f_indices, m_Distances); -// while (clusters.size()>5000) -// { -// MITK_INFO << "Number of clusters: " << clusters.size(); -// MITK_INFO << "Increasing cluster size"; -// for (unsigned int i=0; i > centroids = ResampleFibers(m_InCentroids); if (centroids.empty()) { MITK_INFO << "No fibers in centroid tractogram!"; return; } MITK_INFO << "Clustering with input centroids"; clusters = AddToKnownClusters(f_indices, centroids); no_match = clusters.back(); clusters.pop_back(); MITK_INFO << "Number of clusters: " << clusters.size(); MergeDuplicateClusters(clusters); } MITK_INFO << "Clustering finished"; int max = clusters.size()-1; if (m_MaxClusters>0 && clusters.size()-1>m_MaxClusters) max = m_MaxClusters; for (int i=clusters.size()-1; i>=0; --i) { Cluster c = clusters.at(i); if ( c.n>=(int)m_MinClusterSize && !(m_MaxClusters>0 && clusters.size()-i>m_MaxClusters) ) { m_OutClusters.push_back(c); vtkSmartPointer weights = vtkSmartPointer::New(); vtkSmartPointer pTmp = m_Tractogram->GeneratePolyDataByIds(c.I, weights); mitk::FiberBundle::Pointer fib = mitk::FiberBundle::New(pTmp); if (max>0) fib->SetFiberWeights((float)i/max); m_OutTractograms.push_back(fib); m_OutFiberIndices.push_back(c.I); // create centroid vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); vtkSmartPointer polyData = vtkSmartPointer::New(); vtkSmartPointer container = vtkSmartPointer::New(); vnl_matrix centroid_points = c.h / c.n; for (unsigned int j=0; jInsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); polyData->SetPoints(vtkNewPoints); polyData->SetLines(vtkNewCells); mitk::FiberBundle::Pointer centroid = mitk::FiberBundle::New(polyData); centroid->SetFiberColors(255, 255, 255); m_OutCentroids.push_back(centroid); } } MITK_INFO << "Final number of clusters: " << m_OutTractograms.size(); int w = 0; for (auto fib : m_OutTractograms) { if (m_OutTractograms.size()>1) { fib->SetFiberWeights((float)w/(m_OutTractograms.size()-1)); m_OutCentroids.at(w)->SetFiberWeights((float)w/(m_OutTractograms.size()-1)); } else { fib->SetFiberWeights(1); m_OutCentroids.at(w)->SetFiberWeights(1); } fib->ColorFibersByFiberWeights(false, false); ++w; } if (no_match.n>0) { vtkSmartPointer weights = vtkSmartPointer::New(); vtkSmartPointer pTmp = m_Tractogram->GeneratePolyDataByIds(no_match.I, weights); mitk::FiberBundle::Pointer fib = mitk::FiberBundle::New(pTmp); fib->SetFiberColors(0, 0, 0); m_OutFiberIndices.push_back(no_match.I); m_OutTractograms.push_back(fib); } } } diff --git a/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.cpp b/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.cpp index a77e966134..2c8ac8ca6c 100755 --- a/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.cpp +++ b/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.cpp @@ -1,2517 +1,2546 @@ /*=================================================================== 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 "mitkFiberBundle.h" #include #include #include #include "mitkImagePixelReadAccessor.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include const char* mitk::FiberBundle::FIBER_ID_ARRAY = "Fiber_IDs"; mitk::FiberBundle::FiberBundle( vtkPolyData* fiberPolyData ) : m_NumFibers(0) { m_FiberWeights = vtkSmartPointer::New(); m_FiberWeights->SetName("FIBER_WEIGHTS"); m_FiberPolyData = vtkSmartPointer::New(); if (fiberPolyData != nullptr) m_FiberPolyData = fiberPolyData; else { this->m_FiberPolyData->SetPoints(vtkSmartPointer::New()); this->m_FiberPolyData->SetLines(vtkSmartPointer::New()); } this->UpdateFiberGeometry(); this->GenerateFiberIds(); this->ColorFibersByOrientation(); } mitk::FiberBundle::~FiberBundle() { } mitk::FiberBundle::Pointer mitk::FiberBundle::GetDeepCopy() { mitk::FiberBundle::Pointer newFib = mitk::FiberBundle::New(m_FiberPolyData); newFib->SetFiberColors(this->m_FiberColors); newFib->SetFiberWeights(this->m_FiberWeights); return newFib; } vtkSmartPointer mitk::FiberBundle::GeneratePolyDataByIds(std::vector fiberIds, vtkSmartPointer weights) { vtkSmartPointer newFiberPolyData = vtkSmartPointer::New(); vtkSmartPointer newLineSet = vtkSmartPointer::New(); vtkSmartPointer newPointSet = vtkSmartPointer::New(); weights->SetNumberOfValues(fiberIds.size()); int counter = 0; auto finIt = fiberIds.begin(); while ( finIt != fiberIds.end() ) { if (*finIt < 0 || *finIt>GetNumFibers()){ MITK_INFO << "FiberID can not be negative or >NumFibers!!! check id Extraction!" << *finIt; break; } vtkSmartPointer fiber = m_FiberIdDataSet->GetCell(*finIt);//->DeepCopy(fiber); vtkSmartPointer fibPoints = fiber->GetPoints(); vtkSmartPointer newFiber = vtkSmartPointer::New(); newFiber->GetPointIds()->SetNumberOfIds( fibPoints->GetNumberOfPoints() ); for(int i=0; iGetNumberOfPoints(); i++) { newFiber->GetPointIds()->SetId(i, newPointSet->GetNumberOfPoints()); newPointSet->InsertNextPoint(fibPoints->GetPoint(i)[0], fibPoints->GetPoint(i)[1], fibPoints->GetPoint(i)[2]); } weights->InsertValue(counter, this->GetFiberWeight(*finIt)); newLineSet->InsertNextCell(newFiber); ++finIt; ++counter; } newFiberPolyData->SetPoints(newPointSet); newFiberPolyData->SetLines(newLineSet); return newFiberPolyData; } // merge two fiber bundles mitk::FiberBundle::Pointer mitk::FiberBundle::AddBundles(std::vector< mitk::FiberBundle::Pointer > fibs) { vtkSmartPointer vNewPolyData = vtkSmartPointer::New(); vtkSmartPointer vNewLines = vtkSmartPointer::New(); vtkSmartPointer vNewPoints = vtkSmartPointer::New(); // add current fiber bundle vtkSmartPointer weights = vtkSmartPointer::New(); int num_weights = this->GetNumFibers(); for (auto fib : fibs) num_weights += fib->GetNumFibers(); weights->SetNumberOfValues(num_weights); unsigned int counter = 0; for (int i=0; iGetNumberOfCells(); i++) { vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j, p); vtkIdType id = vNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } weights->InsertValue(counter, this->GetFiberWeight(i)); vNewLines->InsertNextCell(container); counter++; } for (auto fib : fibs) { // add new fiber bundle for (int i=0; iGetFiberPolyData()->GetNumberOfCells(); i++) { vtkCell* cell = fib->GetFiberPolyData()->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j, p); vtkIdType id = vNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } weights->InsertValue(counter, fib->GetFiberWeight(i)); vNewLines->InsertNextCell(container); counter++; } } // initialize PolyData vNewPolyData->SetPoints(vNewPoints); vNewPolyData->SetLines(vNewLines); // initialize fiber bundle mitk::FiberBundle::Pointer newFib = mitk::FiberBundle::New(vNewPolyData); newFib->SetFiberWeights(weights); return newFib; } // merge two fiber bundles mitk::FiberBundle::Pointer mitk::FiberBundle::AddBundle(mitk::FiberBundle* fib) { if (fib==nullptr) return this->GetDeepCopy(); MITK_INFO << "Adding fibers"; vtkSmartPointer vNewPolyData = vtkSmartPointer::New(); vtkSmartPointer vNewLines = vtkSmartPointer::New(); vtkSmartPointer vNewPoints = vtkSmartPointer::New(); // add current fiber bundle vtkSmartPointer weights = vtkSmartPointer::New(); weights->SetNumberOfValues(this->GetNumFibers()+fib->GetNumFibers()); unsigned int counter = 0; for (int i=0; iGetNumberOfCells(); i++) { vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j, p); vtkIdType id = vNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } weights->InsertValue(counter, this->GetFiberWeight(i)); vNewLines->InsertNextCell(container); counter++; } // add new fiber bundle for (int i=0; iGetFiberPolyData()->GetNumberOfCells(); i++) { vtkCell* cell = fib->GetFiberPolyData()->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j, p); vtkIdType id = vNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } weights->InsertValue(counter, fib->GetFiberWeight(i)); vNewLines->InsertNextCell(container); counter++; } // initialize PolyData vNewPolyData->SetPoints(vNewPoints); vNewPolyData->SetLines(vNewLines); // initialize fiber bundle mitk::FiberBundle::Pointer newFib = mitk::FiberBundle::New(vNewPolyData); newFib->SetFiberWeights(weights); return newFib; } // Only retain fibers with a weight larger than the specified threshold mitk::FiberBundle::Pointer mitk::FiberBundle::FilterByWeights(float weight_thr, bool invert) { vtkSmartPointer vNewPolyData = vtkSmartPointer::New(); vtkSmartPointer vNewLines = vtkSmartPointer::New(); vtkSmartPointer vNewPoints = vtkSmartPointer::New(); std::vector weights; for (int i=0; iGetNumFibers(); i++) { if ( (invert && this->GetFiberWeight(i)>weight_thr) || (!invert && this->GetFiberWeight(i)<=weight_thr)) continue; vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j, p); vtkIdType id = vNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vNewLines->InsertNextCell(container); weights.push_back(this->GetFiberWeight(i)); } // initialize PolyData vNewPolyData->SetPoints(vNewPoints); vNewPolyData->SetLines(vNewLines); // initialize fiber bundle mitk::FiberBundle::Pointer newFib = mitk::FiberBundle::New(vNewPolyData); for (unsigned int i=0; iSetFiberWeight(i, weights.at(i)); return newFib; } // Only retain a subsample of the fibers mitk::FiberBundle::Pointer mitk::FiberBundle::SubsampleFibers(float factor) { vtkSmartPointer vNewPolyData = vtkSmartPointer::New(); vtkSmartPointer vNewLines = vtkSmartPointer::New(); vtkSmartPointer vNewPoints = vtkSmartPointer::New(); int new_num_fibs = this->GetNumFibers()*factor; MITK_INFO << "Subsampling fibers with factor " << factor << "(" << new_num_fibs << "/" << this->GetNumFibers() << ")"; // add current fiber bundle vtkSmartPointer weights = vtkSmartPointer::New(); weights->SetNumberOfValues(new_num_fibs); std::vector< int > ids; for (int i=0; iGetNumFibers(); i++) ids.push_back(i); std::random_shuffle(ids.begin(), ids.end()); unsigned int counter = 0; for (int i=0; iGetCell(ids.at(i)); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j, p); vtkIdType id = vNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } weights->InsertValue(counter, this->GetFiberWeight(ids.at(i))); vNewLines->InsertNextCell(container); counter++; } // initialize PolyData vNewPolyData->SetPoints(vNewPoints); vNewPolyData->SetLines(vNewLines); // initialize fiber bundle mitk::FiberBundle::Pointer newFib = mitk::FiberBundle::New(vNewPolyData); newFib->SetFiberWeights(weights); return newFib; } // subtract two fiber bundles mitk::FiberBundle::Pointer mitk::FiberBundle::SubtractBundle(mitk::FiberBundle* fib) { if (fib==nullptr) return this->GetDeepCopy(); MITK_INFO << "Subtracting fibers"; vtkSmartPointer vNewPolyData = vtkSmartPointer::New(); vtkSmartPointer vNewLines = vtkSmartPointer::New(); vtkSmartPointer vNewPoints = vtkSmartPointer::New(); std::vector< std::vector< itk::Point > > points1; for( int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (points==nullptr || numPoints<=0) continue; itk::Point start = GetItkPoint(points->GetPoint(0)); itk::Point end = GetItkPoint(points->GetPoint(numPoints-1)); points1.push_back( {start, end} ); } std::vector< std::vector< itk::Point > > points2; for( int i=0; iGetNumFibers(); i++ ) { vtkCell* cell = fib->GetFiberPolyData()->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (points==nullptr || numPoints<=0) continue; itk::Point start = GetItkPoint(points->GetPoint(0)); itk::Point end = GetItkPoint(points->GetPoint(numPoints-1)); points2.push_back( {start, end} ); } // int progress = 0; std::vector< int > ids; #pragma omp parallel for for (int i=0; i<(int)points1.size(); i++) { //#pragma omp critical // { // progress++; // std::cout << (int)(100*(float)progress/points1.size()) << "%" << '\r'; // cout.flush(); // } bool match = false; for (unsigned int j=0; jGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (points==nullptr || numPoints<=0) continue; vtkSmartPointer container = vtkSmartPointer::New(); for( int j=0; jInsertNextPoint(points->GetPoint(j)); container->GetPointIds()->InsertNextId(id); } vNewLines->InsertNextCell(container); } if(vNewLines->GetNumberOfCells()==0) return mitk::FiberBundle::New(); // initialize PolyData vNewPolyData->SetPoints(vNewPoints); vNewPolyData->SetLines(vNewLines); // initialize fiber bundle return mitk::FiberBundle::New(vNewPolyData); } itk::Point mitk::FiberBundle::GetItkPoint(double point[3]) { itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; return itkPoint; } /* * set PolyData (additional flag to recompute fiber geometry, default = true) */ void mitk::FiberBundle::SetFiberPolyData(vtkSmartPointer fiberPD, bool updateGeometry) { if (fiberPD == nullptr) this->m_FiberPolyData = vtkSmartPointer::New(); else m_FiberPolyData->DeepCopy(fiberPD); m_NumFibers = m_FiberPolyData->GetNumberOfLines(); if (updateGeometry) UpdateFiberGeometry(); GenerateFiberIds(); ColorFibersByOrientation(); } /* * return vtkPolyData */ vtkSmartPointer mitk::FiberBundle::GetFiberPolyData() const { return m_FiberPolyData; } void mitk::FiberBundle::ColorFibersByOrientation() { //===== FOR WRITING A TEST ======================== // colorT size == tupelComponents * tupelElements // compare color results // to cover this code 100% also PolyData needed, where colorarray already exists // + one fiber with exactly 1 point // + one fiber with 0 points //================================================= vtkPoints* extrPoints = nullptr; extrPoints = m_FiberPolyData->GetPoints(); int numOfPoints = 0; if (extrPoints!=nullptr) numOfPoints = extrPoints->GetNumberOfPoints(); //colors and alpha value for each single point, RGBA = 4 components unsigned char rgba[4] = {0,0,0,0}; int componentSize = 4; m_FiberColors = vtkSmartPointer::New(); m_FiberColors->Allocate(numOfPoints * componentSize); m_FiberColors->SetNumberOfComponents(componentSize); m_FiberColors->SetName("FIBER_COLORS"); int numOfFibers = m_FiberPolyData->GetNumberOfLines(); if (numOfFibers < 1) return; /* extract single fibers of fiberBundle */ vtkCellArray* fiberList = m_FiberPolyData->GetLines(); fiberList->InitTraversal(); for (int fi=0; fiGetNextCell(pointsPerFiber, idList); /* single fiber checkpoints: is number of points valid */ if (pointsPerFiber > 1) { /* operate on points of single fiber */ for (int i=0; i 0) { /* The color value of the current point is influenced by the previous point and next point. */ vnl_vector_fixed< double, 3 > currentPntvtk(extrPoints->GetPoint(idList[i])[0], extrPoints->GetPoint(idList[i])[1],extrPoints->GetPoint(idList[i])[2]); vnl_vector_fixed< double, 3 > nextPntvtk(extrPoints->GetPoint(idList[i+1])[0], extrPoints->GetPoint(idList[i+1])[1], extrPoints->GetPoint(idList[i+1])[2]); vnl_vector_fixed< double, 3 > prevPntvtk(extrPoints->GetPoint(idList[i-1])[0], extrPoints->GetPoint(idList[i-1])[1], extrPoints->GetPoint(idList[i-1])[2]); vnl_vector_fixed< double, 3 > diff1; diff1 = currentPntvtk - nextPntvtk; vnl_vector_fixed< double, 3 > diff2; diff2 = currentPntvtk - prevPntvtk; vnl_vector_fixed< double, 3 > diff; diff = (diff1 - diff2) / 2.0; diff.normalize(); rgba[0] = (unsigned char) (255.0 * std::fabs(diff[0])); rgba[1] = (unsigned char) (255.0 * std::fabs(diff[1])); rgba[2] = (unsigned char) (255.0 * std::fabs(diff[2])); rgba[3] = (unsigned char) (255.0); } else if (i==0) { /* First point has no previous point, therefore only diff1 is taken */ vnl_vector_fixed< double, 3 > currentPntvtk(extrPoints->GetPoint(idList[i])[0], extrPoints->GetPoint(idList[i])[1],extrPoints->GetPoint(idList[i])[2]); vnl_vector_fixed< double, 3 > nextPntvtk(extrPoints->GetPoint(idList[i+1])[0], extrPoints->GetPoint(idList[i+1])[1], extrPoints->GetPoint(idList[i+1])[2]); vnl_vector_fixed< double, 3 > diff1; diff1 = currentPntvtk - nextPntvtk; diff1.normalize(); rgba[0] = (unsigned char) (255.0 * std::fabs(diff1[0])); rgba[1] = (unsigned char) (255.0 * std::fabs(diff1[1])); rgba[2] = (unsigned char) (255.0 * std::fabs(diff1[2])); rgba[3] = (unsigned char) (255.0); } else if (i==pointsPerFiber-1) { /* Last point has no next point, therefore only diff2 is taken */ vnl_vector_fixed< double, 3 > currentPntvtk(extrPoints->GetPoint(idList[i])[0], extrPoints->GetPoint(idList[i])[1],extrPoints->GetPoint(idList[i])[2]); vnl_vector_fixed< double, 3 > prevPntvtk(extrPoints->GetPoint(idList[i-1])[0], extrPoints->GetPoint(idList[i-1])[1], extrPoints->GetPoint(idList[i-1])[2]); vnl_vector_fixed< double, 3 > diff2; diff2 = currentPntvtk - prevPntvtk; diff2.normalize(); rgba[0] = (unsigned char) (255.0 * std::fabs(diff2[0])); rgba[1] = (unsigned char) (255.0 * std::fabs(diff2[1])); rgba[2] = (unsigned char) (255.0 * std::fabs(diff2[2])); rgba[3] = (unsigned char) (255.0); } m_FiberColors->InsertTypedTuple(idList[i], rgba); } } else if (pointsPerFiber == 1) { /* a single point does not define a fiber (use vertex mechanisms instead */ continue; } else { MITK_DEBUG << "Fiber with 0 points detected... please check your tractography algorithm!" ; continue; } } m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } void mitk::FiberBundle::ColorFibersByCurvature(bool, bool normalize) { double window = 5; //colors and alpha value for each single point, RGBA = 4 components unsigned char rgba[4] = {0,0,0,0}; int componentSize = 4; m_FiberColors = vtkSmartPointer::New(); m_FiberColors->Allocate(m_FiberPolyData->GetNumberOfPoints() * componentSize); m_FiberColors->SetNumberOfComponents(componentSize); m_FiberColors->SetName("FIBER_COLORS"); mitk::LookupTable::Pointer mitkLookup = mitk::LookupTable::New(); vtkSmartPointer lookupTable = vtkSmartPointer::New(); lookupTable->SetTableRange(0.0, 0.8); lookupTable->Build(); mitkLookup->SetVtkLookupTable(lookupTable); mitkLookup->SetType(mitk::LookupTable::JET); std::vector< double > values; double min = 1; double max = 0; MITK_INFO << "Coloring fibers by curvature"; boost::progress_display disp(m_FiberPolyData->GetNumberOfCells()); for (int i=0; iGetNumberOfCells(); i++) { ++disp; vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); // calculate curvatures for (int j=0; j > vectors; vnl_vector_fixed< float, 3 > meanV; meanV.fill(0.0); while(dist1) { double p1[3]; points->GetPoint(c-1, p1); double p2[3]; points->GetPoint(c, p2); vnl_vector_fixed< float, 3 > v; v[0] = p2[0]-p1[0]; v[1] = p2[1]-p1[1]; v[2] = p2[2]-p1[2]; dist += v.magnitude(); v.normalize(); vectors.push_back(v); if (c==j) meanV += v; c--; } c = j; dist = 0; while(distGetPoint(c, p1); double p2[3]; points->GetPoint(c+1, p2); vnl_vector_fixed< float, 3 > v; v[0] = p2[0]-p1[0]; v[1] = p2[1]-p1[1]; v[2] = p2[2]-p1[2]; dist += v.magnitude(); v.normalize(); vectors.push_back(v); if (c==j) meanV += v; c++; } meanV.normalize(); double dev = 0; for (unsigned int c=0; c1.0) angle = 1.0; if (angle<-1.0) angle = -1.0; dev += acos(angle)*180/M_PI; } if (vectors.size()>0) dev /= vectors.size(); dev = 1.0-dev/180.0; values.push_back(dev); if (devmax) max = dev; } } unsigned int count = 0; for (int i=0; iGetNumberOfCells(); i++) { vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); for (int j=0; j1) dev = 1; lookupTable->GetColor(dev, color); rgba[0] = (unsigned char) (255.0 * color[0]); rgba[1] = (unsigned char) (255.0 * color[1]); rgba[2] = (unsigned char) (255.0 * color[2]); rgba[3] = (unsigned char) (255.0); m_FiberColors->InsertTypedTuple(cell->GetPointId(j), rgba); count++; } } m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } void mitk::FiberBundle::SetFiberOpacity(vtkDoubleArray* FAValArray) { for(long i=0; iGetNumberOfTuples(); i++) { double faValue = FAValArray->GetValue(i); faValue = faValue * 255.0; m_FiberColors->SetComponent(i,3, (unsigned char) faValue ); } m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } void mitk::FiberBundle::ResetFiberOpacity() { for(long i=0; iGetNumberOfTuples(); i++) m_FiberColors->SetComponent(i,3, 255.0 ); m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } void mitk::FiberBundle::ColorFibersByScalarMap(mitk::Image::Pointer FAimage, bool opacity, bool normalize) { mitkPixelTypeMultiplex3( ColorFibersByScalarMap, FAimage->GetPixelType(), FAimage, opacity, normalize ); m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } template void mitk::FiberBundle::ColorFibersByScalarMap(const mitk::PixelType, mitk::Image::Pointer image, bool opacity, bool normalize) { m_FiberColors = vtkSmartPointer::New(); m_FiberColors->Allocate(m_FiberPolyData->GetNumberOfPoints() * 4); m_FiberColors->SetNumberOfComponents(4); m_FiberColors->SetName("FIBER_COLORS"); mitk::ImagePixelReadAccessor readimage(image, image->GetVolumeData(0)); unsigned char rgba[4] = {0,0,0,0}; vtkPoints* pointSet = m_FiberPolyData->GetPoints(); mitk::LookupTable::Pointer mitkLookup = mitk::LookupTable::New(); vtkSmartPointer lookupTable = vtkSmartPointer::New(); lookupTable->SetTableRange(0.0, 0.8); lookupTable->Build(); mitkLookup->SetVtkLookupTable(lookupTable); mitkLookup->SetType(mitk::LookupTable::JET); double min = 9999999; double max = -9999999; for(long i=0; iGetNumberOfPoints(); ++i) { Point3D px; px[0] = pointSet->GetPoint(i)[0]; px[1] = pointSet->GetPoint(i)[1]; px[2] = pointSet->GetPoint(i)[2]; double pixelValue = readimage.GetPixelByWorldCoordinates(px); if (pixelValue>max) max = pixelValue; if (pixelValueGetNumberOfPoints(); ++i) { Point3D px; px[0] = pointSet->GetPoint(i)[0]; px[1] = pointSet->GetPoint(i)[1]; px[2] = pointSet->GetPoint(i)[2]; double pixelValue = readimage.GetPixelByWorldCoordinates(px); if (normalize) pixelValue = (pixelValue-min)/(max-min); else if (pixelValue>1) pixelValue = 1; double color[3]; lookupTable->GetColor(1-pixelValue, color); rgba[0] = (unsigned char) (255.0 * color[0]); rgba[1] = (unsigned char) (255.0 * color[1]); rgba[2] = (unsigned char) (255.0 * color[2]); if (opacity) rgba[3] = (unsigned char) (255.0 * pixelValue); else rgba[3] = (unsigned char) (255.0); m_FiberColors->InsertTypedTuple(i, rgba); } m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } void mitk::FiberBundle::ColorFibersByFiberWeights(bool opacity, bool normalize) { m_FiberColors = vtkSmartPointer::New(); m_FiberColors->Allocate(m_FiberPolyData->GetNumberOfPoints() * 4); m_FiberColors->SetNumberOfComponents(4); m_FiberColors->SetName("FIBER_COLORS"); mitk::LookupTable::Pointer mitkLookup = mitk::LookupTable::New(); vtkSmartPointer lookupTable = vtkSmartPointer::New(); lookupTable->SetTableRange(0.0, 0.8); lookupTable->Build(); mitkLookup->SetVtkLookupTable(lookupTable); mitkLookup->SetType(mitk::LookupTable::JET); unsigned char rgba[4] = {0,0,0,0}; unsigned int counter = 0; float max = -999999; float min = 999999; for (int i=0; iGetFiberWeight(i); if (weight>max) max = weight; if (weightGetCell(i); int numPoints = cell->GetNumberOfPoints(); double weight = this->GetFiberWeight(i); for (int j=0; j1) v = 1; double color[3]; lookupTable->GetColor(1-v, color); rgba[0] = (unsigned char) (255.0 * color[0]); rgba[1] = (unsigned char) (255.0 * color[1]); rgba[2] = (unsigned char) (255.0 * color[2]); if (opacity) rgba[3] = (unsigned char) (255.0 * v); else rgba[3] = (unsigned char) (255.0); m_FiberColors->InsertTypedTuple(counter, rgba); counter++; } } m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } void mitk::FiberBundle::SetFiberColors(float r, float g, float b, float alpha) { m_FiberColors = vtkSmartPointer::New(); m_FiberColors->Allocate(m_FiberPolyData->GetNumberOfPoints() * 4); m_FiberColors->SetNumberOfComponents(4); m_FiberColors->SetName("FIBER_COLORS"); unsigned char rgba[4] = {0,0,0,0}; for(long i=0; iGetNumberOfPoints(); ++i) { rgba[0] = (unsigned char) r; rgba[1] = (unsigned char) g; rgba[2] = (unsigned char) b; rgba[3] = (unsigned char) alpha; m_FiberColors->InsertTypedTuple(i, rgba); } m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } void mitk::FiberBundle::GenerateFiberIds() { if (m_FiberPolyData == nullptr) return; vtkSmartPointer idFiberFilter = vtkSmartPointer::New(); idFiberFilter->SetInputData(m_FiberPolyData); idFiberFilter->CellIdsOn(); // idFiberFilter->PointIdsOn(); // point id's are not needed idFiberFilter->SetIdsArrayName(FIBER_ID_ARRAY); idFiberFilter->FieldDataOn(); idFiberFilter->Update(); m_FiberIdDataSet = idFiberFilter->GetOutput(); } float mitk::FiberBundle::GetOverlap(ItkUcharImgType* mask, bool do_resampling) { vtkSmartPointer PolyData = m_FiberPolyData; mitk::FiberBundle::Pointer fibCopy = this; if (do_resampling) { float minSpacing = 1; if(mask->GetSpacing()[0]GetSpacing()[1] && mask->GetSpacing()[0]GetSpacing()[2]) minSpacing = mask->GetSpacing()[0]; else if (mask->GetSpacing()[1] < mask->GetSpacing()[2]) minSpacing = mask->GetSpacing()[1]; else minSpacing = mask->GetSpacing()[2]; fibCopy = this->GetDeepCopy(); fibCopy->ResampleLinear(minSpacing/5); PolyData = fibCopy->GetFiberPolyData(); } MITK_INFO << "Calculating overlap"; int inside = 0; int outside = 0; boost::progress_display disp(m_NumFibers); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); for (int j=0; jGetPoint(j); itk::Point itkP; itkP[0] = p[0]; itkP[1] = p[1]; itkP[2] = p[2]; itk::Index<3> idx; mask->TransformPhysicalPointToIndex(itkP, idx); if ( mask->GetLargestPossibleRegion().IsInside(idx) && mask->GetPixel(idx) != 0 ) inside++; else outside++; } } if (inside+outside==0) outside = 1; return (float)inside/(inside+outside); } mitk::FiberBundle::Pointer mitk::FiberBundle::RemoveFibersOutside(ItkUcharImgType* mask, bool invert) { float minSpacing = 1; if(mask->GetSpacing()[0]GetSpacing()[1] && mask->GetSpacing()[0]GetSpacing()[2]) minSpacing = mask->GetSpacing()[0]; else if (mask->GetSpacing()[1] < mask->GetSpacing()[2]) minSpacing = mask->GetSpacing()[1]; else minSpacing = mask->GetSpacing()[2]; mitk::FiberBundle::Pointer fibCopy = this->GetDeepCopy(); fibCopy->ResampleLinear(minSpacing/10); vtkSmartPointer PolyData =fibCopy->GetFiberPolyData(); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); MITK_INFO << "Cutting fibers"; boost::progress_display disp(m_NumFibers); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); if (numPoints>1) { int newNumPoints = 0; for (int j=0; jGetPoint(j); itk::Point itkP; itkP[0] = p[0]; itkP[1] = p[1]; itkP[2] = p[2]; itk::Index<3> idx; mask->TransformPhysicalPointToIndex(itkP, idx); if ( mask->GetPixel(idx) != 0 && mask->GetLargestPossibleRegion().IsInside(idx) && !invert ) { vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); newNumPoints++; } else if ( (mask->GetPixel(idx) == 0 || !mask->GetLargestPossibleRegion().IsInside(idx)) && invert ) { vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); newNumPoints++; } else if (newNumPoints>0) { vtkNewCells->InsertNextCell(container); newNumPoints = 0; container = vtkSmartPointer::New(); } } if (newNumPoints>0) vtkNewCells->InsertNextCell(container); } } if (vtkNewCells->GetNumberOfCells()<=0) return nullptr; vtkSmartPointer newPolyData = vtkSmartPointer::New(); newPolyData->SetPoints(vtkNewPoints); newPolyData->SetLines(vtkNewCells); mitk::FiberBundle::Pointer newFib = mitk::FiberBundle::New(newPolyData); newFib->Compress(0.1); return newFib; } mitk::FiberBundle::Pointer mitk::FiberBundle::ExtractFiberSubset(DataNode* roi, DataStorage* storage) { if (roi==nullptr || !(dynamic_cast(roi->GetData()) || dynamic_cast(roi->GetData())) ) return nullptr; std::vector tmp = ExtractFiberIdSubset(roi, storage); if (tmp.size()<=0) return mitk::FiberBundle::New(); vtkSmartPointer weights = vtkSmartPointer::New(); vtkSmartPointer pTmp = GeneratePolyDataByIds(tmp, weights); mitk::FiberBundle::Pointer fib = mitk::FiberBundle::New(pTmp); fib->SetFiberWeights(weights); return fib; } std::vector mitk::FiberBundle::ExtractFiberIdSubset(DataNode *roi, DataStorage* storage) { std::vector result; if (roi==nullptr || roi->GetData()==nullptr) return result; mitk::PlanarFigureComposite::Pointer pfc = dynamic_cast(roi->GetData()); if (!pfc.IsNull()) // handle composite { DataStorage::SetOfObjects::ConstPointer children = storage->GetDerivations(roi); if (children->size()==0) return result; switch (pfc->getOperationType()) { case 0: // AND { MITK_INFO << "AND"; result = this->ExtractFiberIdSubset(children->ElementAt(0), storage); std::vector::iterator it; for (unsigned int i=1; iSize(); ++i) { std::vector inRoi = this->ExtractFiberIdSubset(children->ElementAt(i), storage); std::vector rest(std::min(result.size(),inRoi.size())); it = std::set_intersection(result.begin(), result.end(), inRoi.begin(), inRoi.end(), rest.begin() ); rest.resize( it - rest.begin() ); result = rest; } break; } case 1: // OR { MITK_INFO << "OR"; result = ExtractFiberIdSubset(children->ElementAt(0), storage); std::vector::iterator it; for (unsigned int i=1; iSize(); ++i) { it = result.end(); std::vector inRoi = ExtractFiberIdSubset(children->ElementAt(i), storage); result.insert(it, inRoi.begin(), inRoi.end()); } // remove duplicates sort(result.begin(), result.end()); it = unique(result.begin(), result.end()); result.resize( it - result.begin() ); break; } case 2: // NOT { MITK_INFO << "NOT"; for(long i=0; iGetNumFibers(); i++) result.push_back(i); std::vector::iterator it; for (unsigned int i=0; iSize(); ++i) { std::vector inRoi = ExtractFiberIdSubset(children->ElementAt(i), storage); std::vector rest(result.size()-inRoi.size()); it = std::set_difference(result.begin(), result.end(), inRoi.begin(), inRoi.end(), rest.begin() ); rest.resize( it - rest.begin() ); result = rest; } break; } } } else if ( dynamic_cast(roi->GetData()) ) // actual extraction { if ( dynamic_cast(roi->GetData()) ) { mitk::PlanarFigure::Pointer planarPoly = dynamic_cast(roi->GetData()); //create vtkPolygon using controlpoints from planarFigure polygon vtkSmartPointer polygonVtk = vtkSmartPointer::New(); for (unsigned int i=0; iGetNumberOfControlPoints(); ++i) { itk::Point p = planarPoly->GetWorldControlPoint(i); vtkIdType id = polygonVtk->GetPoints()->InsertNextPoint(p[0], p[1], p[2] ); polygonVtk->GetPointIds()->InsertNextId(id); } MITK_INFO << "Extracting with polygon"; boost::progress_display disp(m_NumFibers); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); for (int j=0; jGetPoint(j, p1); double p2[3] = {0,0,0}; points->GetPoint(j+1, p2); double tolerance = 0.001; // Outputs double t = 0; // Parametric coordinate of intersection (0 (corresponding to p1) to 1 (corresponding to p2)) double x[3] = {0,0,0}; // The coordinate of the intersection double pcoords[3] = {0,0,0}; int subId = 0; int iD = polygonVtk->IntersectWithLine(p1, p2, tolerance, t, x, pcoords, subId); if (iD!=0) { result.push_back(i); break; } } } } else if ( dynamic_cast(roi->GetData()) ) { mitk::PlanarFigure::Pointer planarFigure = dynamic_cast(roi->GetData()); Vector3D planeNormal = planarFigure->GetPlaneGeometry()->GetNormal(); planeNormal.Normalize(); //calculate circle radius mitk::Point3D V1w = planarFigure->GetWorldControlPoint(0); //centerPoint mitk::Point3D V2w = planarFigure->GetWorldControlPoint(1); //radiusPoint double radius = V1w.EuclideanDistanceTo(V2w); radius *= radius; MITK_INFO << "Extracting with circle"; boost::progress_display disp(m_NumFibers); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); for (int j=0; jGetPoint(j, p1); double p2[3] = {0,0,0}; points->GetPoint(j+1, p2); // Outputs double t = 0; // Parametric coordinate of intersection (0 (corresponding to p1) to 1 (corresponding to p2)) double x[3] = {0,0,0}; // The coordinate of the intersection int iD = vtkPlane::IntersectWithLine(p1,p2,planeNormal.GetDataPointer(),V1w.GetDataPointer(),t,x); if (iD!=0) { double dist = (x[0]-V1w[0])*(x[0]-V1w[0])+(x[1]-V1w[1])*(x[1]-V1w[1])+(x[2]-V1w[2])*(x[2]-V1w[2]); if( dist <= radius) { result.push_back(i); break; } } } } } return result; } return result; } void mitk::FiberBundle::UpdateFiberGeometry() { vtkSmartPointer cleaner = vtkSmartPointer::New(); cleaner->SetInputData(m_FiberPolyData); cleaner->PointMergingOff(); cleaner->Update(); m_FiberPolyData = cleaner->GetOutput(); m_FiberLengths.clear(); m_MeanFiberLength = 0; m_MedianFiberLength = 0; m_LengthStDev = 0; m_NumFibers = m_FiberPolyData->GetNumberOfCells(); if (m_FiberColors==nullptr || m_FiberColors->GetNumberOfTuples()!=m_FiberPolyData->GetNumberOfPoints()) this->ColorFibersByOrientation(); if (m_FiberWeights->GetNumberOfValues()!=m_NumFibers) { m_FiberWeights = vtkSmartPointer::New(); m_FiberWeights->SetName("FIBER_WEIGHTS"); m_FiberWeights->SetNumberOfValues(m_NumFibers); this->SetFiberWeights(1); } if (m_NumFibers<=0) // no fibers present; apply default geometry { m_MinFiberLength = 0; m_MaxFiberLength = 0; mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New(); geometry->SetImageGeometry(false); float b[] = {0, 1, 0, 1, 0, 1}; geometry->SetFloatBounds(b); SetGeometry(geometry); return; } double b[6]; m_FiberPolyData->GetBounds(b); // calculate statistics for (int i=0; iGetNumberOfCells(); i++) { vtkCell* cell = m_FiberPolyData->GetCell(i); int p = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); float length = 0; for (int j=0; jGetPoint(j, p1); double p2[3]; points->GetPoint(j+1, p2); float dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2])); length += dist; } m_FiberLengths.push_back(length); m_MeanFiberLength += length; if (i==0) { m_MinFiberLength = length; m_MaxFiberLength = length; } else { if (lengthm_MaxFiberLength) m_MaxFiberLength = length; } } m_MeanFiberLength /= m_NumFibers; std::vector< float > sortedLengths = m_FiberLengths; std::sort(sortedLengths.begin(), sortedLengths.end()); for (int i=0; i1) m_LengthStDev /= (m_NumFibers-1); else m_LengthStDev = 0; m_LengthStDev = std::sqrt(m_LengthStDev); m_MedianFiberLength = sortedLengths.at(m_NumFibers/2); mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New(); geometry->SetFloatBounds(b); this->SetGeometry(geometry); m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } float mitk::FiberBundle::GetFiberWeight(unsigned int fiber) const { return m_FiberWeights->GetValue(fiber); } void mitk::FiberBundle::SetFiberWeights(float newWeight) { for (int i=0; iGetNumberOfValues(); i++) m_FiberWeights->SetValue(i, newWeight); } void mitk::FiberBundle::SetFiberWeights(vtkSmartPointer weights) { if (m_NumFibers!=weights->GetNumberOfValues()) { MITK_INFO << "Weights array not equal to number of fibers! " << weights->GetNumberOfValues() << " vs " << m_NumFibers; return; } for (int i=0; iGetNumberOfValues(); i++) m_FiberWeights->SetValue(i, weights->GetValue(i)); m_FiberWeights->SetName("FIBER_WEIGHTS"); } void mitk::FiberBundle::SetFiberWeight(unsigned int fiber, float weight) { m_FiberWeights->SetValue(fiber, weight); } void mitk::FiberBundle::SetFiberColors(vtkSmartPointer fiberColors) { for(long i=0; iGetNumberOfPoints(); ++i) { unsigned char source[4] = {0,0,0,0}; fiberColors->GetTypedTuple(i, source); unsigned char target[4] = {0,0,0,0}; target[0] = source[0]; target[1] = source[1]; target[2] = source[2]; target[3] = source[3]; m_FiberColors->InsertTypedTuple(i, target); } m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } itk::Matrix< double, 3, 3 > mitk::FiberBundle::TransformMatrix(itk::Matrix< double, 3, 3 > m, double rx, double ry, double rz) { rx = rx*M_PI/180; ry = ry*M_PI/180; rz = rz*M_PI/180; itk::Matrix< double, 3, 3 > rotX; rotX.SetIdentity(); rotX[1][1] = cos(rx); rotX[2][2] = rotX[1][1]; rotX[1][2] = -sin(rx); rotX[2][1] = -rotX[1][2]; itk::Matrix< double, 3, 3 > rotY; rotY.SetIdentity(); rotY[0][0] = cos(ry); rotY[2][2] = rotY[0][0]; rotY[0][2] = sin(ry); rotY[2][0] = -rotY[0][2]; itk::Matrix< double, 3, 3 > rotZ; rotZ.SetIdentity(); rotZ[0][0] = cos(rz); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(rz); rotZ[1][0] = -rotZ[0][1]; itk::Matrix< double, 3, 3 > rot = rotZ*rotY*rotX; m = rot*m; return m; } itk::Point mitk::FiberBundle::TransformPoint(vnl_vector_fixed< double, 3 > point, double rx, double ry, double rz, double tx, double ty, double tz) { rx = rx*M_PI/180; ry = ry*M_PI/180; rz = rz*M_PI/180; vnl_matrix_fixed< double, 3, 3 > rotX; rotX.set_identity(); rotX[1][1] = cos(rx); rotX[2][2] = rotX[1][1]; rotX[1][2] = -sin(rx); rotX[2][1] = -rotX[1][2]; vnl_matrix_fixed< double, 3, 3 > rotY; rotY.set_identity(); rotY[0][0] = cos(ry); rotY[2][2] = rotY[0][0]; rotY[0][2] = sin(ry); rotY[2][0] = -rotY[0][2]; vnl_matrix_fixed< double, 3, 3 > rotZ; rotZ.set_identity(); rotZ[0][0] = cos(rz); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(rz); rotZ[1][0] = -rotZ[0][1]; vnl_matrix_fixed< double, 3, 3 > rot = rotZ*rotY*rotX; mitk::BaseGeometry::Pointer geom = this->GetGeometry(); mitk::Point3D center = geom->GetCenter(); point[0] -= center[0]; point[1] -= center[1]; point[2] -= center[2]; point = rot*point; point[0] += center[0]+tx; point[1] += center[1]+ty; point[2] += center[2]+tz; itk::Point out; out[0] = point[0]; out[1] = point[1]; out[2] = point[2]; return out; } + +void mitk::FiberBundle::TransformFibers(itk::ScalableAffineTransform< mitk::ScalarType >::Pointer transform) +{ + vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); + vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); + + for (int i=0; iGetCell(i); + int numPoints = cell->GetNumberOfPoints(); + vtkPoints* points = cell->GetPoints(); + + vtkSmartPointer container = vtkSmartPointer::New(); + for (int j=0; j p = GetItkPoint(points->GetPoint(j)); + p = transform->TransformPoint(p); + vtkIdType id = vtkNewPoints->InsertNextPoint(p.GetDataPointer()); + container->GetPointIds()->InsertNextId(id); + } + vtkNewCells->InsertNextCell(container); + } + + m_FiberPolyData = vtkSmartPointer::New(); + m_FiberPolyData->SetPoints(vtkNewPoints); + m_FiberPolyData->SetLines(vtkNewCells); + this->SetFiberPolyData(m_FiberPolyData, true); +} + void mitk::FiberBundle::TransformFibers(double rx, double ry, double rz, double tx, double ty, double tz) { rx = rx*M_PI/180; ry = ry*M_PI/180; rz = rz*M_PI/180; vnl_matrix_fixed< double, 3, 3 > rotX; rotX.set_identity(); rotX[1][1] = cos(rx); rotX[2][2] = rotX[1][1]; rotX[1][2] = -sin(rx); rotX[2][1] = -rotX[1][2]; vnl_matrix_fixed< double, 3, 3 > rotY; rotY.set_identity(); rotY[0][0] = cos(ry); rotY[2][2] = rotY[0][0]; rotY[0][2] = sin(ry); rotY[2][0] = -rotY[0][2]; vnl_matrix_fixed< double, 3, 3 > rotZ; rotZ.set_identity(); rotZ[0][0] = cos(rz); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(rz); rotZ[1][0] = -rotZ[0][1]; vnl_matrix_fixed< double, 3, 3 > rot = rotZ*rotY*rotX; mitk::BaseGeometry::Pointer geom = this->GetGeometry(); mitk::Point3D center = geom->GetCenter(); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j); vnl_vector_fixed< double, 3 > dir; dir[0] = p[0]-center[0]; dir[1] = p[1]-center[1]; dir[2] = p[2]-center[2]; dir = rot*dir; dir[0] += center[0]+tx; dir[1] += center[1]+ty; dir[2] += center[2]+tz; vtkIdType id = vtkNewPoints->InsertNextPoint(dir.data_block()); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); } void mitk::FiberBundle::RotateAroundAxis(double x, double y, double z) { x = x*M_PI/180; y = y*M_PI/180; z = z*M_PI/180; vnl_matrix_fixed< double, 3, 3 > rotX; rotX.set_identity(); rotX[1][1] = cos(x); rotX[2][2] = rotX[1][1]; rotX[1][2] = -sin(x); rotX[2][1] = -rotX[1][2]; vnl_matrix_fixed< double, 3, 3 > rotY; rotY.set_identity(); rotY[0][0] = cos(y); rotY[2][2] = rotY[0][0]; rotY[0][2] = sin(y); rotY[2][0] = -rotY[0][2]; vnl_matrix_fixed< double, 3, 3 > rotZ; rotZ.set_identity(); rotZ[0][0] = cos(z); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(z); rotZ[1][0] = -rotZ[0][1]; mitk::BaseGeometry::Pointer geom = this->GetGeometry(); mitk::Point3D center = geom->GetCenter(); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j); vnl_vector_fixed< double, 3 > dir; dir[0] = p[0]-center[0]; dir[1] = p[1]-center[1]; dir[2] = p[2]-center[2]; dir = rotZ*rotY*rotX*dir; dir[0] += center[0]; dir[1] += center[1]; dir[2] += center[2]; vtkIdType id = vtkNewPoints->InsertNextPoint(dir.data_block()); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); } void mitk::FiberBundle::ScaleFibers(double x, double y, double z, bool subtractCenter) { MITK_INFO << "Scaling fibers"; boost::progress_display disp(m_NumFibers); mitk::BaseGeometry* geom = this->GetGeometry(); mitk::Point3D c = geom->GetCenter(); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j); if (subtractCenter) { p[0] -= c[0]; p[1] -= c[1]; p[2] -= c[2]; } p[0] *= x; p[1] *= y; p[2] *= z; if (subtractCenter) { p[0] += c[0]; p[1] += c[1]; p[2] += c[2]; } vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); } void mitk::FiberBundle::TranslateFibers(double x, double y, double z) { vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j); p[0] += x; p[1] += y; p[2] += z; vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); } void mitk::FiberBundle::MirrorFibers(unsigned int axis) { if (axis>2) return; MITK_INFO << "Mirroring fibers"; boost::progress_display disp(m_NumFibers); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j); p[axis] = -p[axis]; vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); } void mitk::FiberBundle::RemoveDir(vnl_vector_fixed dir, double threshold) { dir.normalize(); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); boost::progress_display disp(m_FiberPolyData->GetNumberOfCells()); for (int i=0; iGetNumberOfCells(); i++) { ++disp ; vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); // calculate curvatures vtkSmartPointer container = vtkSmartPointer::New(); bool discard = false; for (int j=0; jGetPoint(j, p1); double p2[3]; points->GetPoint(j+1, p2); vnl_vector_fixed< double, 3 > v1; v1[0] = p2[0]-p1[0]; v1[1] = p2[1]-p1[1]; v1[2] = p2[2]-p1[2]; if (v1.magnitude()>0.001) { v1.normalize(); if (fabs(dot_product(v1,dir))>threshold) { discard = true; break; } } } if (!discard) { for (int j=0; jGetPoint(j, p1); vtkIdType id = vtkNewPoints->InsertNextPoint(p1); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); // UpdateColorCoding(); // UpdateFiberGeometry(); } bool mitk::FiberBundle::ApplyCurvatureThreshold(float minRadius, bool deleteFibers) { if (minRadius<0) return true; vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); MITK_INFO << "Applying curvature threshold"; boost::progress_display disp(m_FiberPolyData->GetNumberOfCells()); for (int i=0; iGetNumberOfCells(); i++) { ++disp ; vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); // calculate curvatures vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j, p1); double p2[3]; points->GetPoint(j+1, p2); double p3[3]; points->GetPoint(j+2, p3); vnl_vector_fixed< float, 3 > v1, v2, v3; v1[0] = p2[0]-p1[0]; v1[1] = p2[1]-p1[1]; v1[2] = p2[2]-p1[2]; v2[0] = p3[0]-p2[0]; v2[1] = p3[1]-p2[1]; v2[2] = p3[2]-p2[2]; v3[0] = p1[0]-p3[0]; v3[1] = p1[1]-p3[1]; v3[2] = p1[2]-p3[2]; float a = v1.magnitude(); float b = v2.magnitude(); float c = v3.magnitude(); float r = a*b*c/std::sqrt((a+b+c)*(a+b-c)*(b+c-a)*(a-b+c)); // radius of triangle via Heron's formula (area of triangle) vtkIdType id = vtkNewPoints->InsertNextPoint(p1); container->GetPointIds()->InsertNextId(id); if (deleteFibers && rInsertNextCell(container); container = vtkSmartPointer::New(); } else if (j==numPoints-3) { id = vtkNewPoints->InsertNextPoint(p2); container->GetPointIds()->InsertNextId(id); id = vtkNewPoints->InsertNextPoint(p3); container->GetPointIds()->InsertNextId(id); vtkNewCells->InsertNextCell(container); } } } if (vtkNewCells->GetNumberOfCells()<=0) return false; m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); return true; } bool mitk::FiberBundle::RemoveShortFibers(float lengthInMM) { MITK_INFO << "Removing short fibers"; if (lengthInMM<=0 || lengthInMMm_MaxFiberLength) // can't remove all fibers { MITK_WARN << "Process aborted. No fibers would be left!"; return false; } vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); float min = m_MaxFiberLength; boost::progress_display disp(m_NumFibers); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (m_FiberLengths.at(i)>=lengthInMM) { vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j); vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); if (m_FiberLengths.at(i)GetNumberOfCells()<=0) return false; m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); return true; } bool mitk::FiberBundle::RemoveLongFibers(float lengthInMM) { if (lengthInMM<=0 || lengthInMM>m_MaxFiberLength) return true; if (lengthInMM vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); MITK_INFO << "Removing long fibers"; boost::progress_display disp(m_NumFibers); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (m_FiberLengths.at(i)<=lengthInMM) { vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j); vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } } if (vtkNewCells->GetNumberOfCells()<=0) return false; m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); return true; } void mitk::FiberBundle::ResampleSpline(float pointDistance, double tension, double continuity, double bias ) { if (pointDistance<=0) return; vtkSmartPointer vtkSmoothPoints = vtkSmartPointer::New(); //in smoothpoints the interpolated points representing a fiber are stored. //in vtkcells all polylines are stored, actually all id's of them are stored vtkSmartPointer vtkSmoothCells = vtkSmartPointer::New(); //cellcontainer for smoothed lines MITK_INFO << "Smoothing fibers"; vtkSmartPointer newFiberWeights = vtkSmartPointer::New(); newFiberWeights->SetName("FIBER_WEIGHTS"); newFiberWeights->SetNumberOfValues(m_NumFibers); std::vector< vtkSmartPointer > resampled_streamlines; resampled_streamlines.resize(m_NumFibers); boost::progress_display disp(m_NumFibers); #pragma omp parallel for for (int i=0; i newPoints = vtkSmartPointer::New(); float length = 0; #pragma omp critical { length = m_FiberLengths.at(i); ++disp; vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); for (int j=0; jInsertNextPoint(points->GetPoint(j)); } int sampling = std::ceil(length/pointDistance); vtkSmartPointer xSpline = vtkSmartPointer::New(); vtkSmartPointer ySpline = vtkSmartPointer::New(); vtkSmartPointer zSpline = vtkSmartPointer::New(); xSpline->SetDefaultBias(bias); xSpline->SetDefaultTension(tension); xSpline->SetDefaultContinuity(continuity); ySpline->SetDefaultBias(bias); ySpline->SetDefaultTension(tension); ySpline->SetDefaultContinuity(continuity); zSpline->SetDefaultBias(bias); zSpline->SetDefaultTension(tension); zSpline->SetDefaultContinuity(continuity); vtkSmartPointer spline = vtkSmartPointer::New(); spline->SetXSpline(xSpline); spline->SetYSpline(ySpline); spline->SetZSpline(zSpline); spline->SetPoints(newPoints); vtkSmartPointer functionSource = vtkSmartPointer::New(); functionSource->SetParametricFunction(spline); functionSource->SetUResolution(sampling); functionSource->SetVResolution(sampling); functionSource->SetWResolution(sampling); functionSource->Update(); vtkPolyData* outputFunction = functionSource->GetOutput(); vtkPoints* tmpSmoothPnts = outputFunction->GetPoints(); //smoothPoints of current fiber vtkSmartPointer smoothLine = vtkSmartPointer::New(); #pragma omp critical { for (int j=0; jGetNumberOfPoints(); j++) { vtkIdType id = vtkSmoothPoints->InsertNextPoint(tmpSmoothPnts->GetPoint(j)); smoothLine->GetPointIds()->InsertNextId(id); } resampled_streamlines[i] = smoothLine; } } for (auto container : resampled_streamlines) { vtkSmoothCells->InsertNextCell(container); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkSmoothPoints); m_FiberPolyData->SetLines(vtkSmoothCells); this->SetFiberPolyData(m_FiberPolyData, true); } void mitk::FiberBundle::ResampleSpline(float pointDistance) { ResampleSpline(pointDistance, 0, 0, 0 ); } unsigned long mitk::FiberBundle::GetNumberOfPoints() const { unsigned long points = 0; for (int i=0; iGetNumberOfCells(); i++) { vtkCell* cell = m_FiberPolyData->GetCell(i); points += cell->GetNumberOfPoints(); } return points; } void mitk::FiberBundle::Compress(float error) { vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); MITK_INFO << "Compressing fibers"; unsigned long numRemovedPoints = 0; boost::progress_display disp(m_FiberPolyData->GetNumberOfCells()); vtkSmartPointer newFiberWeights = vtkSmartPointer::New(); newFiberWeights->SetName("FIBER_WEIGHTS"); newFiberWeights->SetNumberOfValues(m_NumFibers); #pragma omp parallel for for (int i=0; iGetNumberOfCells(); i++) { std::vector< vnl_vector_fixed< double, 3 > > vertices; float weight = 1; #pragma omp critical { ++disp; weight = m_FiberWeights->GetValue(i); vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); for (int j=0; jGetPoint(j, cand); vnl_vector_fixed< double, 3 > candV; candV[0]=cand[0]; candV[1]=cand[1]; candV[2]=cand[2]; vertices.push_back(candV); } } // calculate curvatures int numPoints = vertices.size(); std::vector< int > removedPoints; removedPoints.resize(numPoints, 0); removedPoints[0]=-1; removedPoints[numPoints-1]=-1; vtkSmartPointer container = vtkSmartPointer::New(); int remCounter = 0; bool pointFound = true; while (pointFound) { pointFound = false; double minError = error; int removeIndex = -1; for (unsigned int j=0; j candV = vertices.at(j); int validP = -1; vnl_vector_fixed< double, 3 > pred; for (int k=j-1; k>=0; k--) if (removedPoints[k]<=0) { pred = vertices.at(k); validP = k; break; } int validS = -1; vnl_vector_fixed< double, 3 > succ; for (int k=j+1; k=0 && validS>=0) { double a = (candV-pred).magnitude(); double b = (candV-succ).magnitude(); double c = (pred-succ).magnitude(); double s=0.5*(a+b+c); double hc=(2.0/c)*sqrt(fabs(s*(s-a)*(s-b)*(s-c))); if (hcInsertNextPoint(vertices.at(j).data_block()); container->GetPointIds()->InsertNextId(id); } } } #pragma omp critical { newFiberWeights->SetValue(vtkNewCells->GetNumberOfCells(), weight); numRemovedPoints += remCounter; vtkNewCells->InsertNextCell(container); } } if (vtkNewCells->GetNumberOfCells()>0) { MITK_INFO << "Removed points: " << numRemovedPoints; SetFiberWeights(newFiberWeights); m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); } } void mitk::FiberBundle::ResampleToNumPoints(unsigned int targetPoints) { if (targetPoints<2) mitkThrow() << "Minimum two points required for resampling!"; MITK_INFO << "Resampling fibers (number of points " << targetPoints << ")"; bool unequal_fibs = true; while (unequal_fibs) { vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); vtkSmartPointer newFiberWeights = vtkSmartPointer::New(); newFiberWeights->SetName("FIBER_WEIGHTS"); newFiberWeights->SetNumberOfValues(m_NumFibers); unequal_fibs = false; //#pragma omp parallel for for (int i=0; iGetNumberOfCells(); i++) { std::vector< vnl_vector_fixed< double, 3 > > vertices; float weight = 1; double seg_len = 0; //#pragma omp critical { weight = m_FiberWeights->GetValue(i); vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); if ((unsigned int)numPoints!=targetPoints) seg_len = this->GetFiberLength(i)/(targetPoints-1);; vtkPoints* points = cell->GetPoints(); for (int j=0; jGetPoint(j, cand); vnl_vector_fixed< double, 3 > candV; candV[0]=cand[0]; candV[1]=cand[1]; candV[2]=cand[2]; vertices.push_back(candV); } } vtkSmartPointer container = vtkSmartPointer::New(); vnl_vector_fixed< double, 3 > lastV = vertices.at(0); //#pragma omp critical { vtkIdType id = vtkNewPoints->InsertNextPoint(lastV.data_block()); container->GetPointIds()->InsertNextId(id); } for (unsigned int j=1; j vec = vertices.at(j) - lastV; double new_dist = vec.magnitude(); if (new_dist >= seg_len && seg_len>0) { vnl_vector_fixed< double, 3 > newV = lastV; if ( new_dist-seg_len <= mitk::eps ) { vec.normalize(); newV += vec * seg_len; } else { // intersection between sphere (radius 'pointDistance', center 'lastV') and line (direction 'd' and point 'p') vnl_vector_fixed< double, 3 > p = vertices.at(j-1); vnl_vector_fixed< double, 3 > d = vertices.at(j) - p; double a = d[0]*d[0] + d[1]*d[1] + d[2]*d[2]; double b = 2 * (d[0] * (p[0] - lastV[0]) + d[1] * (p[1] - lastV[1]) + d[2] * (p[2] - lastV[2])); double c = (p[0] - lastV[0])*(p[0] - lastV[0]) + (p[1] - lastV[1])*(p[1] - lastV[1]) + (p[2] - lastV[2])*(p[2] - lastV[2]) - seg_len*seg_len; double v1 =(-b + std::sqrt(b*b-4*a*c))/(2*a); double v2 =(-b - std::sqrt(b*b-4*a*c))/(2*a); if (v1>0) newV = p + d * v1; else if (v2>0) newV = p + d * v2; else MITK_INFO << "ERROR1 - linear resampling"; j--; } //#pragma omp critical { vtkIdType id = vtkNewPoints->InsertNextPoint(newV.data_block()); container->GetPointIds()->InsertNextId(id); } lastV = newV; } else if ( (j==vertices.size()-1 && new_dist>0.0001) || seg_len==0) { //#pragma omp critical { vtkIdType id = vtkNewPoints->InsertNextPoint(vertices.at(j).data_block()); container->GetPointIds()->InsertNextId(id); } } } //#pragma omp critical { newFiberWeights->SetValue(vtkNewCells->GetNumberOfCells(), weight); vtkNewCells->InsertNextCell(container); if (container->GetNumberOfPoints()!=targetPoints) unequal_fibs = true; } } if (vtkNewCells->GetNumberOfCells()>0) { SetFiberWeights(newFiberWeights); m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); } } } void mitk::FiberBundle::ResampleLinear(double pointDistance) { vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); MITK_INFO << "Resampling fibers (linear)"; boost::progress_display disp(m_FiberPolyData->GetNumberOfCells()); vtkSmartPointer newFiberWeights = vtkSmartPointer::New(); newFiberWeights->SetName("FIBER_WEIGHTS"); newFiberWeights->SetNumberOfValues(m_NumFibers); std::vector< vtkSmartPointer > resampled_streamlines; resampled_streamlines.resize(m_FiberPolyData->GetNumberOfCells()); #pragma omp parallel for for (int i=0; iGetNumberOfCells(); i++) { std::vector< vnl_vector_fixed< double, 3 > > vertices; #pragma omp critical { ++disp; vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); for (int j=0; jGetPoint(j, cand); vnl_vector_fixed< double, 3 > candV; candV[0]=cand[0]; candV[1]=cand[1]; candV[2]=cand[2]; vertices.push_back(candV); } } vtkSmartPointer container = vtkSmartPointer::New(); vnl_vector_fixed< double, 3 > lastV = vertices.at(0); #pragma omp critical { vtkIdType id = vtkNewPoints->InsertNextPoint(lastV.data_block()); container->GetPointIds()->InsertNextId(id); } for (unsigned int j=1; j vec = vertices.at(j) - lastV; double new_dist = vec.magnitude(); if (new_dist >= pointDistance) { vnl_vector_fixed< double, 3 > newV = lastV; if ( new_dist-pointDistance <= mitk::eps ) { vec.normalize(); newV += vec * pointDistance; } else { // intersection between sphere (radius 'pointDistance', center 'lastV') and line (direction 'd' and point 'p') vnl_vector_fixed< double, 3 > p = vertices.at(j-1); vnl_vector_fixed< double, 3 > d = vertices.at(j) - p; double a = d[0]*d[0] + d[1]*d[1] + d[2]*d[2]; double b = 2 * (d[0] * (p[0] - lastV[0]) + d[1] * (p[1] - lastV[1]) + d[2] * (p[2] - lastV[2])); double c = (p[0] - lastV[0])*(p[0] - lastV[0]) + (p[1] - lastV[1])*(p[1] - lastV[1]) + (p[2] - lastV[2])*(p[2] - lastV[2]) - pointDistance*pointDistance; double v1 =(-b + std::sqrt(b*b-4*a*c))/(2*a); double v2 =(-b - std::sqrt(b*b-4*a*c))/(2*a); if (v1>0) newV = p + d * v1; else if (v2>0) newV = p + d * v2; else MITK_INFO << "ERROR1 - linear resampling"; j--; } #pragma omp critical { vtkIdType id = vtkNewPoints->InsertNextPoint(newV.data_block()); container->GetPointIds()->InsertNextId(id); } lastV = newV; } else if (j==vertices.size()-1 && new_dist>0.0001) { #pragma omp critical { vtkIdType id = vtkNewPoints->InsertNextPoint(vertices.at(j).data_block()); container->GetPointIds()->InsertNextId(id); } } } #pragma omp critical { resampled_streamlines[i] = container; } } for (auto container : resampled_streamlines) { vtkNewCells->InsertNextCell(container); } if (vtkNewCells->GetNumberOfCells()>0) { m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); } } // reapply selected colorcoding in case PolyData structure has changed bool mitk::FiberBundle::Equals(mitk::FiberBundle* fib, double eps) { if (fib==nullptr) { MITK_INFO << "Reference bundle is nullptr!"; return false; } if (m_NumFibers!=fib->GetNumFibers()) { MITK_INFO << "Unequal number of fibers!"; MITK_INFO << m_NumFibers << " vs. " << fib->GetNumFibers(); return false; } for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkCell* cell2 = fib->GetFiberPolyData()->GetCell(i); int numPoints2 = cell2->GetNumberOfPoints(); vtkPoints* points2 = cell2->GetPoints(); if (numPoints2!=numPoints) { MITK_INFO << "Unequal number of points in fiber " << i << "!"; MITK_INFO << numPoints2 << " vs. " << numPoints; return false; } for (int j=0; jGetPoint(j); double* p2 = points2->GetPoint(j); if (fabs(p1[0]-p2[0])>eps || fabs(p1[1]-p2[1])>eps || fabs(p1[2]-p2[2])>eps) { MITK_INFO << "Unequal points in fiber " << i << " at position " << j << "!"; MITK_INFO << "p1: " << p1[0] << ", " << p1[1] << ", " << p1[2]; MITK_INFO << "p2: " << p2[0] << ", " << p2[1] << ", " << p2[2]; return false; } } } return true; } void mitk::FiberBundle::PrintSelf(std::ostream &os, itk::Indent indent) const { os << indent << this->GetNameOfClass() << ":\n"; os << indent << "Number of fibers: " << this->GetNumFibers() << std::endl; os << indent << "Min. fiber length: " << this->GetMinFiberLength() << std::endl; os << indent << "Max. fiber length: " << this->GetMaxFiberLength() << std::endl; os << indent << "Mean fiber length: " << this->GetMeanFiberLength() << std::endl; os << indent << "Median fiber length: " << this->GetMedianFiberLength() << std::endl; os << indent << "STDEV fiber length: " << this->GetLengthStDev() << std::endl; os << indent << "Number of points: " << this->GetNumberOfPoints() << std::endl; Superclass::PrintSelf(os, indent); } /* ESSENTIAL IMPLEMENTATION OF SUPERCLASS METHODS */ void mitk::FiberBundle::UpdateOutputInformation() { } void mitk::FiberBundle::SetRequestedRegionToLargestPossibleRegion() { } bool mitk::FiberBundle::RequestedRegionIsOutsideOfTheBufferedRegion() { return false; } bool mitk::FiberBundle::VerifyRequestedRegion() { return true; } void mitk::FiberBundle::SetRequestedRegion(const itk::DataObject* ) { } diff --git a/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.h b/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.h index 7751e2ee65..c679aa4480 100644 --- a/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.h +++ b/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.h @@ -1,181 +1,182 @@ /*=================================================================== 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_FiberBundle_H #define _MITK_FiberBundle_H //includes for MITK datastructure #include #include #include #include #include #include #include //includes storing fiberdata #include #include #include #include #include #include - +#include namespace mitk { /** * \brief Base Class for Fiber Bundles; */ class MITKFIBERTRACKING_EXPORT FiberBundle : public BaseData { public: typedef itk::Image ItkUcharImgType; // fiber colorcodings static const char* FIBER_ID_ARRAY; virtual void UpdateOutputInformation() override; virtual void SetRequestedRegionToLargestPossibleRegion() override; virtual bool RequestedRegionIsOutsideOfTheBufferedRegion() override; virtual bool VerifyRequestedRegion() override; virtual void SetRequestedRegion(const itk::DataObject*) override; mitkClassMacro( FiberBundle, BaseData ) itkFactorylessNewMacro(Self) itkCloneMacro(Self) mitkNewMacro1Param(Self, vtkSmartPointer) // custom constructor // colorcoding related methods void ColorFibersByFiberWeights(bool opacity, bool normalize); void ColorFibersByCurvature(bool opacity, bool normalize); void ColorFibersByScalarMap(mitk::Image::Pointer, bool opacity, bool normalize); template void ColorFibersByScalarMap(const mitk::PixelType pixelType, mitk::Image::Pointer, bool opacity, bool normalize); void ColorFibersByOrientation(); void SetFiberOpacity(vtkDoubleArray *FAValArray); void ResetFiberOpacity(); void SetFiberColors(vtkSmartPointer fiberColors); void SetFiberColors(float r, float g, float b, float alpha=255); vtkSmartPointer GetFiberColors() const { return m_FiberColors; } // fiber compression void Compress(float error = 0.0); // fiber resampling void ResampleSpline(float pointDistance=1); void ResampleSpline(float pointDistance, double tension, double continuity, double bias ); void ResampleLinear(double pointDistance=1); void ResampleToNumPoints(unsigned int targetPoints); mitk::FiberBundle::Pointer FilterByWeights(float weight_thr, bool invert=false); bool RemoveShortFibers(float lengthInMM); bool RemoveLongFibers(float lengthInMM); bool ApplyCurvatureThreshold(float minRadius, bool deleteFibers); void MirrorFibers(unsigned int axis); void RotateAroundAxis(double x, double y, double z); void TranslateFibers(double x, double y, double z); void ScaleFibers(double x, double y, double z, bool subtractCenter=true); void TransformFibers(double rx, double ry, double rz, double tx, double ty, double tz); + void TransformFibers(itk::ScalableAffineTransform< mitk::ScalarType >::Pointer transform); void RemoveDir(vnl_vector_fixed dir, double threshold); itk::Point TransformPoint(vnl_vector_fixed< double, 3 > point, double rx, double ry, double rz, double tx, double ty, double tz); itk::Matrix< double, 3, 3 > TransformMatrix(itk::Matrix< double, 3, 3 > m, double rx, double ry, double rz); // add/subtract fibers FiberBundle::Pointer AddBundle(FiberBundle* fib); mitk::FiberBundle::Pointer AddBundles(std::vector< mitk::FiberBundle::Pointer > fibs); FiberBundle::Pointer SubtractBundle(FiberBundle* fib); // fiber subset extraction FiberBundle::Pointer ExtractFiberSubset(DataNode *roi, DataStorage* storage); std::vector ExtractFiberIdSubset(DataNode* roi, DataStorage* storage); FiberBundle::Pointer RemoveFibersOutside(ItkUcharImgType* mask, bool invert=false); float GetOverlap(ItkUcharImgType* mask, bool do_resampling); mitk::FiberBundle::Pointer SubsampleFibers(float factor); // get/set data float GetFiberLength(int index) const { return m_FiberLengths.at(index); } vtkSmartPointer GetFiberWeights() const { return m_FiberWeights; } float GetFiberWeight(unsigned int fiber) const; void SetFiberWeights(float newWeight); void SetFiberWeight(unsigned int fiber, float weight); void SetFiberWeights(vtkSmartPointer weights); void SetFiberPolyData(vtkSmartPointer, bool updateGeometry = true); vtkSmartPointer GetFiberPolyData() const; itkGetConstMacro( NumFibers, int) //itkGetMacro( FiberSampling, int) itkGetConstMacro( MinFiberLength, float ) itkGetConstMacro( MaxFiberLength, float ) itkGetConstMacro( MeanFiberLength, float ) itkGetConstMacro( MedianFiberLength, float ) itkGetConstMacro( LengthStDev, float ) itkGetConstMacro( UpdateTime2D, itk::TimeStamp ) itkGetConstMacro( UpdateTime3D, itk::TimeStamp ) void RequestUpdate2D(){ m_UpdateTime2D.Modified(); } void RequestUpdate3D(){ m_UpdateTime3D.Modified(); } void RequestUpdate(){ m_UpdateTime2D.Modified(); m_UpdateTime3D.Modified(); } unsigned long GetNumberOfPoints() const; // copy fiber bundle mitk::FiberBundle::Pointer GetDeepCopy(); // compare fiber bundles bool Equals(FiberBundle* fib, double eps=0.01); itkSetMacro( ReferenceGeometry, mitk::BaseGeometry::Pointer ) itkGetConstMacro( ReferenceGeometry, mitk::BaseGeometry::Pointer ) vtkSmartPointer GeneratePolyDataByIds(std::vector fiberIds, vtkSmartPointer weights); protected: FiberBundle( vtkPolyData* fiberPolyData = nullptr ); virtual ~FiberBundle(); void GenerateFiberIds(); itk::Point GetItkPoint(double point[3]); void UpdateFiberGeometry(); virtual void PrintSelf(std::ostream &os, itk::Indent indent) const override; private: // actual fiber container vtkSmartPointer m_FiberPolyData; // contains fiber ids vtkSmartPointer m_FiberIdDataSet; int m_NumFibers; vtkSmartPointer m_FiberColors; vtkSmartPointer m_FiberWeights; std::vector< float > m_FiberLengths; float m_MinFiberLength; float m_MaxFiberLength; float m_MeanFiberLength; float m_MedianFiberLength; float m_LengthStDev; itk::TimeStamp m_UpdateTime2D; itk::TimeStamp m_UpdateTime3D; mitk::BaseGeometry::Pointer m_ReferenceGeometry; }; } // namespace mitk #endif /* _MITK_FiberBundle_H */ diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/ExtractSimilarTracts.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/ExtractSimilarTracts.cpp index fd07b7bac2..a312dd42ac 100644 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/ExtractSimilarTracts.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/ExtractSimilarTracts.cpp @@ -1,240 +1,238 @@ /*=================================================================== 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 typedef itksys::SystemTools ist; typedef itk::Image ItkFloatImgType; mitk::FiberBundle::Pointer LoadFib(std::string filename) { std::vector fibInfile = mitk::IOUtil::Load(filename); if( fibInfile.empty() ) std::cout << "File " << filename << " could not be read!"; mitk::BaseData::Pointer baseData = fibInfile.at(0); return dynamic_cast(baseData.GetPointer()); } ItkFloatImgType::Pointer LoadItkImage(const std::string& filename) { mitk::Image::Pointer img = dynamic_cast(mitk::IOUtil::Load(filename)[0].GetPointer()); ItkFloatImgType::Pointer itkMask = ItkFloatImgType::New(); mitk::CastToItkImage(img, itkMask); return itkMask; } /*! \brief Spatially cluster fibers */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Extract Similar Tracts"); parser.setCategory("Fiber Tracking Evaluation"); parser.setContributor("MIC"); parser.setArgumentPrefix("--", "-"); parser.addArgument("", "i", mitkCommandLineParser::InputFile, "Input:", "input fiber bundle (.fib, .trk, .tck)", us::Any(), false); parser.addArgument("ref_tracts", "", mitkCommandLineParser::StringList, "Ref. Tracts:", "reference tracts (.fib, .trk, .tck)", us::Any(), false); parser.addArgument("ref_masks", "", mitkCommandLineParser::StringList, "Ref. Masks:", "reference bundle masks", us::Any()); parser.addArgument("", "o", mitkCommandLineParser::OutputDirectory, "Output:", "output root", us::Any(), false); parser.addArgument("distance", "", mitkCommandLineParser::Int, "Distance:", "", 10); parser.addArgument("metric", "", mitkCommandLineParser::String, "Metric:", ""); parser.addArgument("subsample", "", mitkCommandLineParser::Float, "Subsampling factor:", "Only use specified fraction of input fibers", 1.0); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; std::string in_fib = us::any_cast(parsedArgs["i"]); std::string out_root = us::any_cast(parsedArgs["o"]); mitkCommandLineParser::StringContainerType ref_bundle_files = us::any_cast(parsedArgs["ref_tracts"]); mitkCommandLineParser::StringContainerType ref_mask_files; if (parsedArgs.count("ref_masks")) ref_mask_files = us::any_cast(parsedArgs["ref_masks"]); if (ref_mask_files.size()>0 && ref_mask_files.size()!=ref_bundle_files.size()) { MITK_INFO << "If reference masks are used, there has to be one mask per reference tract."; return EXIT_FAILURE; } int distance = 10; if (parsedArgs.count("distance")) distance = us::any_cast(parsedArgs["distance"]); std::string metric = "EU_MEAN"; if (parsedArgs.count("metric")) metric = us::any_cast(parsedArgs["metric"]); float subsample = 1.0; if (parsedArgs.count("subsample")) subsample = us::any_cast(parsedArgs["subsample"]); try { mitk::FiberBundle::Pointer fib = LoadFib(in_fib); std::srand(0); if (subsample<1.0) fib = fib->SubsampleFibers(subsample); mitk::FiberBundle::Pointer resampled_fib = fib->GetDeepCopy(); resampled_fib->ResampleToNumPoints(12); std::vector< mitk::FiberBundle::Pointer > ref_fibs; std::vector< ItkFloatImgType::Pointer > ref_masks; for (std::size_t i=0; i distances; distances.push_back(distance); mitk::FiberBundle::Pointer anchor_tractogram = mitk::FiberBundle::New(nullptr); unsigned int c = 0; for (auto ref_fib : ref_fibs) { MITK_INFO << "Extracting " << ist::GetFilenameName(ref_bundle_files.at(c)); // std::streambuf *old = cout.rdbuf(); // <-- save // std::stringstream ss; // std::cout.rdbuf (ss.rdbuf()); // <-- redirect try { itk::TractClusteringFilter::Pointer segmenter = itk::TractClusteringFilter::New(); // calculate centroids from reference bundle { MITK_INFO << "TEST 1"; itk::TractClusteringFilter::Pointer clusterer = itk::TractClusteringFilter::New(); clusterer->SetDistances({10,20,30}); clusterer->SetTractogram(ref_fib); clusterer->SetMetrics({new mitk::ClusteringMetricEuclideanStd()}); clusterer->SetMergeDuplicateThreshold(0.0); clusterer->Update(); MITK_INFO << "TEST 2"; std::vector tracts = clusterer->GetOutCentroids(); ref_fib = mitk::FiberBundle::New(nullptr); ref_fib = ref_fib->AddBundles(tracts); - MITK_INFO << "TEST 3"; mitk::IOUtil::Save(ref_fib, out_root + "centroids_" + ist::GetFilenameName(ref_bundle_files.at(c))); segmenter->SetInCentroids(ref_fib); - MITK_INFO << "TEST 4"; } // segment tract segmenter->SetFilterMask(ref_masks.at(c)); segmenter->SetOverlapThreshold(0.8); segmenter->SetDistances(distances); segmenter->SetTractogram(resampled_fib); segmenter->SetMergeDuplicateThreshold(0.0); segmenter->SetDoResampling(false); if (metric=="EU_MEAN") segmenter->SetMetrics({new mitk::ClusteringMetricEuclideanMean()}); else if (metric=="EU_STD") segmenter->SetMetrics({new mitk::ClusteringMetricEuclideanStd()}); else if (metric=="EU_MAX") segmenter->SetMetrics({new mitk::ClusteringMetricEuclideanMax()}); segmenter->Update(); std::vector< std::vector< long > > clusters = segmenter->GetOutFiberIndices(); if (clusters.size()>0) { vtkSmartPointer weights = vtkSmartPointer::New(); mitk::FiberBundle::Pointer result = mitk::FiberBundle::New(nullptr); std::vector< mitk::FiberBundle::Pointer > result_fibs; for (unsigned int cluster_index=0; cluster_indexGeneratePolyDataByIds(clusters.at(cluster_index), weights))); result = result->AddBundles(result_fibs); anchor_tractogram = anchor_tractogram->AddBundle(result); mitk::IOUtil::Save(result, out_root + "anchor_" + ist::GetFilenameName(ref_bundle_files.at(c))); fib = mitk::FiberBundle::New(fib->GeneratePolyDataByIds(clusters.back(), weights)); resampled_fib = mitk::FiberBundle::New(resampled_fib->GeneratePolyDataByIds(clusters.back(), weights)); } } catch(itk::ExceptionObject& excpt) { MITK_INFO << "Exception while processing " << ist::GetFilenameName(ref_bundle_files.at(c)); MITK_INFO << excpt.GetDescription(); } catch(std::exception& excpt) { MITK_INFO << "Exception while processing " << ist::GetFilenameName(ref_bundle_files.at(c)); MITK_INFO << excpt.what(); } // std::cout.rdbuf (old); // <-- restore if (fib->GetNumFibers()==0) break; ++c; } MITK_INFO << "Streamlines in anchor tractogram: " << anchor_tractogram->GetNumFibers(); mitk::IOUtil::Save(anchor_tractogram, out_root + "anchor_tractogram.trk"); MITK_INFO << "Streamlines remaining in candidate tractogram: " << fib->GetNumFibers(); mitk::IOUtil::Save(fib, out_root + "candidate_tractogram.trk"); } catch (itk::ExceptionObject e) { std::cout << e; return EXIT_FAILURE; } catch (std::exception e) { std::cout << e.what(); return EXIT_FAILURE; } catch (...) { std::cout << "ERROR!?!"; return EXIT_FAILURE; } return EXIT_SUCCESS; } diff --git a/Modules/ImageStatistics/Testing/mitkImageStatisticsCalculatorTest.cpp b/Modules/ImageStatistics/Testing/mitkImageStatisticsCalculatorTest.cpp index 2db194367a..5854cd3d83 100644 --- a/Modules/ImageStatistics/Testing/mitkImageStatisticsCalculatorTest.cpp +++ b/Modules/ImageStatistics/Testing/mitkImageStatisticsCalculatorTest.cpp @@ -1,1731 +1,1767 @@ /*=================================================================== 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 "mitkImageStatisticsCalculator.h" #include #include #include #include #include #include #include #include #include #include #include /** * \brief Test class for mitkImageStatisticsCalculator * * This test covers: * - instantiation of an ImageStatisticsCalculator class * - correctness of statistics when using PlanarFigures for masking */ class mitkImageStatisticsCalculatorTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkImageStatisticsCalculatorTestSuite); MITK_TEST(TestUninitializedImage); MITK_TEST(TestCase1); MITK_TEST(TestCase2); MITK_TEST(TestCase3); MITK_TEST(TestCase4); MITK_TEST(TestCase5); MITK_TEST(TestCase6); MITK_TEST(TestCase7); MITK_TEST(TestCase8); MITK_TEST(TestCase9); MITK_TEST(TestCase10); MITK_TEST(TestCase11); MITK_TEST(TestCase12); MITK_TEST(TestImageMaskingEmpty); MITK_TEST(TestImageMaskingNonEmpty); MITK_TEST(TestRecomputeOnModifiedMask); MITK_TEST(TestPic3DStatistics); MITK_TEST(TestPic3DAxialPlanarFigureMaskStatistics); MITK_TEST(TestPic3DSagittalPlanarFigureMaskStatistics); MITK_TEST(TestPic3DCoronalPlanarFigureMaskStatistics); MITK_TEST(TestPic3DImageMaskStatistics_label1); MITK_TEST(TestPic3DImageMaskStatistics_label2); MITK_TEST(TestPic3DIgnorePixelValueMaskStatistics); MITK_TEST(TestPic3DSecondaryMaskStatistics); MITK_TEST(TestUS4DCylStatistics_time1); MITK_TEST(TestUS4DCylAxialPlanarFigureMaskStatistics_time1); MITK_TEST(TestUS4DCylSagittalPlanarFigureMaskStatistics_time1); MITK_TEST(TestUS4DCylCoronalPlanarFigureMaskStatistics_time1); MITK_TEST(TestUS4DCylImageMaskStatistics_time1_label_1); MITK_TEST(TestUS4DCylImageMaskStatistics_time2_label_1); MITK_TEST(TestUS4DCylImageMaskStatistics_time1_label_2); MITK_TEST(TestUS4DCylIgnorePixelValueMaskStatistics_time1); MITK_TEST(TestUS4DCylSecondaryMaskStatistics_time1); CPPUNIT_TEST_SUITE_END(); public: void setUp() override; void tearDown() override; void TestUninitializedImage(); void TestCase1(); void TestCase2(); void TestCase3(); void TestCase4(); void TestCase5(); void TestCase6(); void TestCase7(); void TestCase8(); void TestCase9(); void TestCase10(); void TestCase11(); void TestCase12(); void TestImageMaskingEmpty(); void TestImageMaskingNonEmpty(); void TestRecomputeOnModifiedMask(); void TestPic3DStatistics(); void TestPic3DAxialPlanarFigureMaskStatistics(); void TestPic3DSagittalPlanarFigureMaskStatistics(); void TestPic3DCoronalPlanarFigureMaskStatistics(); void TestPic3DImageMaskStatistics_label1(); void TestPic3DImageMaskStatistics_label2(); void TestPic3DIgnorePixelValueMaskStatistics(); void TestPic3DSecondaryMaskStatistics(); void TestUS4DCylStatistics_time1(); void TestUS4DCylAxialPlanarFigureMaskStatistics_time1(); void TestUS4DCylSagittalPlanarFigureMaskStatistics_time1(); void TestUS4DCylCoronalPlanarFigureMaskStatistics_time1(); void TestUS4DCylImageMaskStatistics_time1_label_1(); void TestUS4DCylImageMaskStatistics_time2_label_1(); void TestUS4DCylImageMaskStatistics_time1_label_2(); void TestUS4DCylIgnorePixelValueMaskStatistics_time1(); void TestUS4DCylSecondaryMaskStatistics_time1(); void TestDifferentNBinsForHistogramStatistics(); void TestDifferentBinSizeForHistogramStatistic(); void TestSwitchFromBinSizeToNBins(); void TestSwitchFromNBinsToBinSize(); private: mitk::Image::Pointer m_TestImage; mitk::Image::Pointer m_Pic3DImage; mitk::Image::Pointer m_Pic3DImageMask; mitk::Image::Pointer m_Pic3DImageMask2; mitk::PlanarFigure::Pointer m_Pic3DPlanarFigureAxial; mitk::PlanarFigure::Pointer m_Pic3DPlanarFigureSagittal; mitk::PlanarFigure::Pointer m_Pic3DPlanarFigureCoronal; mitk::Image::Pointer m_US4DImage; mitk::Image::Pointer m_US4DImageMask; mitk::Image::Pointer m_US4DImageMask2; mitk::PlanarFigure::Pointer m_US4DPlanarFigureAxial; mitk::PlanarFigure::Pointer m_US4DPlanarFigureSagittal; mitk::PlanarFigure::Pointer m_US4DPlanarFigureCoronal; mitk::PlaneGeometry::Pointer m_Geometry; // calculate statistics for the given image and planarpolygon const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer ComputeStatistics( mitk::Image::Pointer image, mitk::PlanarFigure::Pointer polygon ); // calculate statistics for the given image and mask const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer ComputeStatistics( mitk::Image::Pointer image, mitk::Image::Pointer image_mask ); // universal function to calculate statistics const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer ComputeStatisticsNew(mitk::Image::Pointer image, int timeStep=0, mitk::MaskGenerator::Pointer maskGen=nullptr, mitk::MaskGenerator::Pointer secondardMaskGen=nullptr, unsigned short label=1); void VerifyStatistics(mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer stats, double testMean, double testSD, double testMedian=0); void VerifyStatistics(mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer stats, long N, double mean, double MPP, double median, double skewness, double kurtosis, double uniformity, double UPP, double variance, double stdev, double min, double max, double RMS, double entropy, vnl_vector minIndex, vnl_vector maxIndex); }; void mitkImageStatisticsCalculatorTestSuite::tearDown() { m_TestImage = nullptr; m_Pic3DImage = nullptr; m_Pic3DImageMask = nullptr; m_Pic3DImageMask2 = nullptr; m_Pic3DPlanarFigureAxial = nullptr; m_Pic3DPlanarFigureSagittal = nullptr; m_Pic3DPlanarFigureCoronal = nullptr; m_US4DImage = nullptr; m_US4DImageMask = nullptr; m_US4DImageMask2 = nullptr; m_US4DPlanarFigureAxial = nullptr; m_US4DPlanarFigureSagittal = nullptr; m_US4DPlanarFigureCoronal = nullptr; m_Geometry = nullptr; } void mitkImageStatisticsCalculatorTestSuite::setUp() { std::string filename = this->GetTestDataFilePath("ImageStatisticsTestData/testimage.dcm"); std::string Pic3DFile = this->GetTestDataFilePath("Pic3D.nrrd"); std::string Pic3DImageMaskFile = this->GetTestDataFilePath("ImageStatisticsTestData/Pic3D-labels.nrrd"); std::string Pic3DImageMaskFile2 = this->GetTestDataFilePath("ImageStatisticsTestData/Pic3D-labels2.nrrd"); std::string Pic3DAxialPlanarFigureFile = this->GetTestDataFilePath("ImageStatisticsTestData/Pic3DAxialPlanarFigure.pf"); std::string Pic3DSagittalPlanarFigureFile = this->GetTestDataFilePath("ImageStatisticsTestData/Pic3DSagittalPlanarFigure.pf"); std::string Pic3DCoronalPlanarFigureFile = this->GetTestDataFilePath("ImageStatisticsTestData/Pic3DCoronalPlanarFigure.pf"); std::string US4DFile = this->GetTestDataFilePath("US4DCyl.nrrd"); std::string US4DImageMaskFile = this->GetTestDataFilePath("ImageStatisticsTestData/US4D-labels.nrrd"); std::string US4DImageMaskFile2 = this->GetTestDataFilePath("ImageStatisticsTestData/US4D-labels2.nrrd"); std::string US4DAxialPlanarFigureFile = this->GetTestDataFilePath("ImageStatisticsTestData/US4DAxialPlanarFigure.pf"); std::string US4DSagittalPlanarFigureFile = this->GetTestDataFilePath("ImageStatisticsTestData/US4DSagittalPlanarFigure.pf"); std::string US4DCoronalPlanarFigureFile = this->GetTestDataFilePath("ImageStatisticsTestData/US4DCoronalPlanarFigure.pf"); if (filename.empty() || Pic3DFile.empty() || Pic3DImageMaskFile.empty() || Pic3DAxialPlanarFigureFile.empty() || Pic3DSagittalPlanarFigureFile.empty() || Pic3DCoronalPlanarFigureFile.empty() || US4DFile.empty() || US4DImageMaskFile.empty() || US4DAxialPlanarFigureFile.empty() || US4DSagittalPlanarFigureFile.empty() || US4DCoronalPlanarFigureFile.empty()) { MITK_TEST_FAILED_MSG( << "Could not find test file" ) } MITK_TEST_OUTPUT(<< "Loading test image '" << filename << "'") m_TestImage = dynamic_cast(mitk::IOUtil::Load(filename)[0].GetPointer()); MITK_TEST_CONDITION_REQUIRED( m_TestImage.IsNotNull(), "Loaded an mitk::Image" ); m_Geometry = m_TestImage->GetSlicedGeometry()->GetPlaneGeometry(0); MITK_TEST_CONDITION_REQUIRED( m_Geometry.IsNotNull(), "Getting image geometry" ); m_Pic3DImage = dynamic_cast(mitk::IOUtil::Load(Pic3DFile)[0].GetPointer()); MITK_TEST_CONDITION_REQUIRED( m_Pic3DImage.IsNotNull(), "Loaded Pic3D" ); m_Pic3DImageMask = dynamic_cast(mitk::IOUtil::Load(Pic3DImageMaskFile)[0].GetPointer()); MITK_TEST_CONDITION_REQUIRED( m_Pic3DImageMask.IsNotNull(), "Loaded Pic3D image mask" ); m_Pic3DImageMask2 = dynamic_cast(mitk::IOUtil::Load(Pic3DImageMaskFile2)[0].GetPointer()); MITK_TEST_CONDITION_REQUIRED( m_Pic3DImageMask2.IsNotNull(), "Loaded Pic3D image secondary mask" ); m_Pic3DPlanarFigureAxial = dynamic_cast(mitk::IOUtil::Load(Pic3DAxialPlanarFigureFile)[0].GetPointer()); MITK_TEST_CONDITION_REQUIRED( m_Pic3DPlanarFigureAxial.IsNotNull(), "Loaded Pic3D axial planarFigure" ); m_Pic3DPlanarFigureSagittal = dynamic_cast(mitk::IOUtil::Load(Pic3DSagittalPlanarFigureFile)[0].GetPointer()); MITK_TEST_CONDITION_REQUIRED( m_Pic3DPlanarFigureSagittal.IsNotNull(), "Loaded Pic3D sagittal planarFigure" ); m_Pic3DPlanarFigureCoronal = dynamic_cast(mitk::IOUtil::Load(Pic3DCoronalPlanarFigureFile)[0].GetPointer()); MITK_TEST_CONDITION_REQUIRED( m_Pic3DPlanarFigureCoronal.IsNotNull(), "Loaded Pic3D coronal planarFigure" ); m_US4DImage = dynamic_cast(mitk::IOUtil::Load(US4DFile)[0].GetPointer()); MITK_TEST_CONDITION_REQUIRED( m_US4DImage.IsNotNull(), "Loaded US4D" ); m_US4DImageMask = dynamic_cast(mitk::IOUtil::Load(US4DImageMaskFile)[0].GetPointer()); MITK_TEST_CONDITION_REQUIRED( m_US4DImageMask.IsNotNull(), "Loaded US4D image mask" ); m_US4DImageMask2 = dynamic_cast(mitk::IOUtil::Load(US4DImageMaskFile2)[0].GetPointer()); MITK_TEST_CONDITION_REQUIRED( m_US4DImageMask2.IsNotNull(), "Loaded US4D image mask2" ); m_US4DPlanarFigureAxial = dynamic_cast(mitk::IOUtil::Load(US4DAxialPlanarFigureFile)[0].GetPointer()); MITK_TEST_CONDITION_REQUIRED( m_US4DPlanarFigureAxial.IsNotNull(), "Loaded US4D axial planarFigure" ); m_US4DPlanarFigureSagittal = dynamic_cast(mitk::IOUtil::Load(US4DSagittalPlanarFigureFile)[0].GetPointer()); MITK_TEST_CONDITION_REQUIRED( m_US4DPlanarFigureSagittal.IsNotNull(), "Loaded US4D sagittal planarFigure" ); m_US4DPlanarFigureCoronal = dynamic_cast(mitk::IOUtil::Load(US4DCoronalPlanarFigureFile)[0].GetPointer()); MITK_TEST_CONDITION_REQUIRED( m_US4DPlanarFigureCoronal.IsNotNull(), "Loaded US4D coronal planarFigure" ); } void mitkImageStatisticsCalculatorTestSuite::TestCase1() { /***************************** * one whole white pixel * -> mean of 255 expected ******************************/ MITK_INFO << std::endl << "Test case 1:-----------------------------------------------------------------------------------"; mitk::PlanarPolygon::Pointer figure1 = mitk::PlanarPolygon::New(); figure1->SetPlaneGeometry( m_Geometry ); mitk::Point2D pnt1; pnt1[0] = 10.5 ; pnt1[1] = 3.5; figure1->PlaceFigure( pnt1 ); mitk::Point2D pnt2; pnt2[0] = 9.5; pnt2[1] = 3.5; figure1->SetControlPoint( 1, pnt2, true ); mitk::Point2D pnt3; pnt3[0] = 9.5; pnt3[1] = 4.5; figure1->SetControlPoint( 2, pnt3, true ); mitk::Point2D pnt4; pnt4[0] = 10.5; pnt4[1] = 4.5; figure1->SetControlPoint( 3, pnt4, true ); figure1->GetPolyLine(0); this->VerifyStatistics(ComputeStatistics(m_TestImage, figure1.GetPointer()), 255.0, 0.0, 255.0); } void mitkImageStatisticsCalculatorTestSuite::TestCase2() { /***************************** * half pixel in x-direction (white) * -> mean of 255 expected ******************************/ MITK_INFO << std::endl << "Test case 2:-----------------------------------------------------------------------------------"; mitk::PlanarPolygon::Pointer figure1 = mitk::PlanarPolygon::New(); figure1->SetPlaneGeometry( m_Geometry ); mitk::Point2D pnt1; pnt1[0] = 10.0 ; pnt1[1] = 3.5; figure1->PlaceFigure( pnt1 ); mitk::Point2D pnt2; pnt2[0] = 9.5; pnt2[1] = 3.5; figure1->SetControlPoint( 1, pnt2, true ); mitk::Point2D pnt3; pnt3[0] = 9.5; pnt3[1] = 4.5; figure1->SetControlPoint( 2, pnt3, true ); mitk::Point2D pnt4; pnt4[0] = 10.0; pnt4[1] = 4.5; figure1->SetControlPoint( 3, pnt4, true ); figure1->GetPolyLine(0); this->VerifyStatistics(ComputeStatistics(m_TestImage, figure1.GetPointer()), 255.0, 0.0, 255.0); } void mitkImageStatisticsCalculatorTestSuite::TestCase3() { /***************************** * half pixel in diagonal-direction (white) * -> mean of 255 expected ******************************/ MITK_INFO << std::endl << "Test case 3:-----------------------------------------------------------------------------------"; mitk::PlanarPolygon::Pointer figure1 = mitk::PlanarPolygon::New(); figure1->SetPlaneGeometry( m_Geometry ); mitk::Point2D pnt1; pnt1[0] = 10.5 ; pnt1[1] = 3.5; figure1->PlaceFigure( pnt1 ); mitk::Point2D pnt2; pnt2[0] = 9.5; pnt2[1] = 3.5; figure1->SetControlPoint( 1, pnt2, true ); mitk::Point2D pnt3; pnt3[0] = 9.5; pnt3[1] = 4.5; figure1->SetControlPoint( 2, pnt3, true ); figure1->GetPolyLine(0); this->VerifyStatistics(ComputeStatistics(m_TestImage, figure1.GetPointer()), 255.0, 0.0, 255.0); } void mitkImageStatisticsCalculatorTestSuite::TestCase4() { /***************************** * one pixel (white) + 2 half pixels (white) + 1 half pixel (black) * -> mean of 191.25 expected ******************************/ MITK_INFO << std::endl << "Test case 4:-----------------------------------------------------------------------------------"; mitk::PlanarPolygon::Pointer figure1 = mitk::PlanarPolygon::New(); figure1->SetPlaneGeometry( m_Geometry ); mitk::Point2D pnt1; pnt1[0] = 1.1; pnt1[1] = 1.1; figure1->PlaceFigure( pnt1 ); mitk::Point2D pnt2; pnt2[0] = 2.0; pnt2[1] = 2.0; figure1->SetControlPoint( 1, pnt2, true ); mitk::Point2D pnt3; pnt3[0] = 3.0; pnt3[1] = 1.0; figure1->SetControlPoint( 2, pnt3, true ); mitk::Point2D pnt4; pnt4[0] = 2.0; pnt4[1] = 0.0; figure1->SetControlPoint( 3, pnt4, true ); figure1->GetPolyLine(0); this->VerifyStatistics(ComputeStatistics(m_TestImage, figure1.GetPointer()), 191.25, 110.41, 242.250); } void mitkImageStatisticsCalculatorTestSuite::TestCase5() { /***************************** * whole pixel (white) + half pixel (gray) in x-direction * -> mean of 191.5 expected ******************************/ MITK_INFO << std::endl << "Test case 5:-----------------------------------------------------------------------------------"; mitk::PlanarPolygon::Pointer figure1 = mitk::PlanarPolygon::New(); figure1->SetPlaneGeometry( m_Geometry ); mitk::Point2D pnt1; pnt1[0] = 11.0; pnt1[1] = 3.5; figure1->PlaceFigure( pnt1 ); mitk::Point2D pnt2; pnt2[0] = 9.5; pnt2[1] = 3.5; figure1->SetControlPoint( 1, pnt2, true ); mitk::Point2D pnt3; pnt3[0] = 9.5; pnt3[1] = 4.5; figure1->SetControlPoint( 2, pnt3, true ); mitk::Point2D pnt4; pnt4[0] = 11.0; pnt4[1] = 4.5; figure1->SetControlPoint( 3, pnt4, true ); figure1->GetPolyLine(0); this->VerifyStatistics(ComputeStatistics(m_TestImage, figure1.GetPointer()), 191.50, 63.50, 134.340); } void mitkImageStatisticsCalculatorTestSuite::TestCase6() { /***************************** * quarter pixel (black) + whole pixel (white) + half pixel (gray) in x-direction * -> mean of 191.5 expected ******************************/ MITK_INFO << std::endl << "Test case 6:-----------------------------------------------------------------------------------"; mitk::PlanarPolygon::Pointer figure1 = mitk::PlanarPolygon::New(); figure1->SetPlaneGeometry( m_Geometry ); mitk::Point2D pnt1; pnt1[0] = 11.0; pnt1[1] = 3.5; figure1->PlaceFigure( pnt1 ); mitk::Point2D pnt2; pnt2[0] = 9.25; pnt2[1] = 3.5; figure1->SetControlPoint( 1, pnt2, true ); mitk::Point2D pnt3; pnt3[0] = 9.25; pnt3[1] = 4.5; figure1->SetControlPoint( 2, pnt3, true ); mitk::Point2D pnt4; pnt4[0] = 11.0; pnt4[1] = 4.5; figure1->SetControlPoint( 3, pnt4, true ); figure1->GetPolyLine(0); this->VerifyStatistics(ComputeStatistics(m_TestImage, figure1.GetPointer()), 191.5, 63.50, 134.340); } void mitkImageStatisticsCalculatorTestSuite::TestCase7() { /***************************** * half pixel (black) + whole pixel (white) + half pixel (gray) in x-direction * -> mean of 127.66 expected ******************************/ MITK_INFO << std::endl << "Test case 7:-----------------------------------------------------------------------------------"; mitk::PlanarPolygon::Pointer figure1 = mitk::PlanarPolygon::New(); figure1->SetPlaneGeometry( m_Geometry ); mitk::Point2D pnt1; pnt1[0] = 11.0; pnt1[1] = 3.5; figure1->PlaceFigure( pnt1 ); mitk::Point2D pnt2; pnt2[0] = 9.0; pnt2[1] = 3.5; figure1->SetControlPoint( 1, pnt2, true ); mitk::Point2D pnt3; pnt3[0] = 9.0; pnt3[1] = 4.0; figure1->SetControlPoint( 2, pnt3, true ); mitk::Point2D pnt4; pnt4[0] = 11.0; pnt4[1] = 4.0; figure1->SetControlPoint( 3, pnt4, true ); figure1->GetPolyLine(0); this->VerifyStatistics(ComputeStatistics(m_TestImage, figure1.GetPointer()), 127.66, 104.1, 140.250); } void mitkImageStatisticsCalculatorTestSuite::TestCase8() { /***************************** * whole pixel (gray) * -> mean of 128 expected ******************************/ MITK_INFO << std::endl << "Test case 8:-----------------------------------------------------------------------------------"; mitk::PlanarPolygon::Pointer figure2 = mitk::PlanarPolygon::New(); figure2->SetPlaneGeometry( m_Geometry ); mitk::Point2D pnt1; pnt1[0] = 11.5; pnt1[1] = 10.5; figure2->PlaceFigure( pnt1 ); mitk::Point2D pnt2; pnt2[0] = 11.5; pnt2[1] = 11.5; figure2->SetControlPoint( 1, pnt2, true ); mitk::Point2D pnt3; pnt3[0] = 12.5; pnt3[1] = 11.5; figure2->SetControlPoint( 2, pnt3, true ); mitk::Point2D pnt4; pnt4[0] = 12.5; pnt4[1] = 10.5; figure2->SetControlPoint( 3, pnt4, true ); figure2->GetPolyLine(0); this->VerifyStatistics(ComputeStatistics(m_TestImage, figure2.GetPointer()), 128.0, 0.0, 128.0); } void mitkImageStatisticsCalculatorTestSuite::TestCase9() { /***************************** * whole pixel (gray) + half pixel (white) in y-direction * -> mean of 191.5 expected ******************************/ MITK_INFO << std::endl << "Test case 9:-----------------------------------------------------------------------------------"; mitk::PlanarPolygon::Pointer figure2 = mitk::PlanarPolygon::New(); figure2->SetPlaneGeometry( m_Geometry ); mitk::Point2D pnt1; pnt1[0] = 11.5; pnt1[1] = 10.5; figure2->PlaceFigure( pnt1 ); mitk::Point2D pnt2; pnt2[0] = 11.5; pnt2[1] = 12.0; figure2->SetControlPoint( 1, pnt2, true ); mitk::Point2D pnt3; pnt3[0] = 12.5; pnt3[1] = 12.0; figure2->SetControlPoint( 2, pnt3, true ); mitk::Point2D pnt4; pnt4[0] = 12.5; pnt4[1] = 10.5; figure2->SetControlPoint( 3, pnt4, true ); figure2->GetPolyLine(0); this->VerifyStatistics(ComputeStatistics(m_TestImage, figure2.GetPointer()), 191.5, 63.50, 134.340); } void mitkImageStatisticsCalculatorTestSuite::TestCase10() { /***************************** * 2 whole pixel (white) + 2 whole pixel (black) in y-direction * -> mean of 127.66 expected ******************************/ MITK_INFO << std::endl << "Test case 10:-----------------------------------------------------------------------------------"; mitk::PlanarPolygon::Pointer figure2 = mitk::PlanarPolygon::New(); figure2->SetPlaneGeometry( m_Geometry ); mitk::Point2D pnt1; pnt1[0] = 11.5; pnt1[1] = 10.5; figure2->PlaceFigure( pnt1 ); mitk::Point2D pnt2; pnt2[0] = 11.5; pnt2[1] = 13.5; figure2->SetControlPoint( 1, pnt2, true ); mitk::Point2D pnt3; pnt3[0] = 12.5; pnt3[1] = 13.5; figure2->SetControlPoint( 2, pnt3, true ); mitk::Point2D pnt4; pnt4[0] = 12.5; pnt4[1] = 10.5; figure2->SetControlPoint( 3, pnt4, true ); figure2->GetPolyLine(0); this->VerifyStatistics(ComputeStatistics(m_TestImage, figure2.GetPointer()), 127.66, 104.1, 140.250); } void mitkImageStatisticsCalculatorTestSuite::TestCase11() { /***************************** * 9 whole pixels (white) + 3 half pixels (white) * + 3 whole pixel (black) [ + 3 slightly less than half pixels (black)] * -> mean of 204.0 expected ******************************/ MITK_INFO << std::endl << "Test case 11:-----------------------------------------------------------------------------------"; mitk::PlanarPolygon::Pointer figure2 = mitk::PlanarPolygon::New(); figure2->SetPlaneGeometry( m_Geometry ); mitk::Point2D pnt1; pnt1[0] = 0.5; pnt1[1] = 0.5; figure2->PlaceFigure( pnt1 ); mitk::Point2D pnt2; pnt2[0] = 3.5; pnt2[1] = 3.5; figure2->SetControlPoint( 1, pnt2, true ); mitk::Point2D pnt3; pnt3[0] = 8.4999; pnt3[1] = 3.5; figure2->SetControlPoint( 2, pnt3, true ); mitk::Point2D pnt4; pnt4[0] = 5.4999; pnt4[1] = 0.5; figure2->SetControlPoint( 3, pnt4, true ); figure2->GetPolyLine(0); this->VerifyStatistics(ComputeStatistics(m_TestImage, figure2.GetPointer()), 204.0, 102.00, 242.250); } void mitkImageStatisticsCalculatorTestSuite::TestCase12() { /***************************** * half pixel (white) + whole pixel (white) + half pixel (black) * -> mean of 212.66 expected ******************************/ MITK_INFO << std::endl << "Test case 12:-----------------------------------------------------------------------------------"; mitk::PlanarPolygon::Pointer figure2 = mitk::PlanarPolygon::New(); figure2->SetPlaneGeometry( m_Geometry ); mitk::Point2D pnt1; pnt1[0] = 9.5; pnt1[1] = 0.5; figure2->PlaceFigure( pnt1 ); mitk::Point2D pnt2; pnt2[0] = 9.5; pnt2[1] = 2.5; figure2->SetControlPoint( 1, pnt2, true ); mitk::Point2D pnt3; pnt3[0] = 11.5; pnt3[1] = 2.5; figure2->SetControlPoint( 2, pnt3, true ); figure2->GetPolyLine(0); this->VerifyStatistics(ComputeStatistics(m_TestImage, figure2.GetPointer()), 212.66, 59.860, 248.640); } void mitkImageStatisticsCalculatorTestSuite::TestImageMaskingEmpty() { MITK_INFO << std::endl << "TestImageMaskingEmpty:-----------------------------------------------------------------------------------"; mitk::Image::Pointer mask_image = mitk::ImageGenerator::GenerateImageFromReference( m_TestImage, 0 ); this->VerifyStatistics( ComputeStatistics( m_TestImage, mask_image ), -21474836.480, -21474836.480, -21474836.480); // empty statisticsContainer (default values) } void mitkImageStatisticsCalculatorTestSuite::TestImageMaskingNonEmpty() { MITK_INFO << std::endl << "TestImageMaskingNonEmpty:-----------------------------------------------------------------------------------"; mitk::Image::Pointer mask_image = mitk::ImageGenerator::GenerateImageFromReference( m_TestImage, 0 ); - std::vector< itk::Index<3U> > activated_indices; - itk::Index<3U> index = {{10, 8, 0}}; - activated_indices.push_back( index ); + // activate voxel in the mask image + if (mask_image->GetDimension() == 3) + { + std::vector< itk::Index<3U> > activated_indices; + itk::Index<3U> index = { { 10, 8, 0 } }; + activated_indices.push_back(index); - index[0] = 9; index[1] = 8; index[2] = 0; - activated_indices.push_back( index ); + index[0] = 9; index[1] = 8; index[2] = 0; + activated_indices.push_back(index); - index[0] = 9; index[1] = 7; index[2] = 0; - activated_indices.push_back( index ); + index[0] = 9; index[1] = 7; index[2] = 0; + activated_indices.push_back(index); - index[0] = 10; index[1] = 7; index[2] = 0; - activated_indices.push_back( index ); + index[0] = 10; index[1] = 7; index[2] = 0; + activated_indices.push_back(index); - std::vector< itk::Index<3U> >::const_iterator indexIter = activated_indices.begin(); + std::vector< itk::Index<3U> >::const_iterator indexIter = activated_indices.begin(); - // activate voxel in the mask image - mitk::ImagePixelWriteAccessor< unsigned char, 3> writeAccess( mask_image ); - while( indexIter != activated_indices.end() ) + mitk::ImagePixelWriteAccessor< unsigned char, 3> writeAccess(mask_image); + while (indexIter != activated_indices.end()) + { + writeAccess.SetPixelByIndex((*indexIter++), 1); + } + } + if (mask_image->GetDimension() == 4) { - writeAccess.SetPixelByIndex( (*indexIter++), 1); + std::vector< itk::Index<4U> > activated_indices; + itk::Index<4U> index = { { 10, 8, 0, 0 } }; + activated_indices.push_back(index); + + index[0] = 9; index[1] = 8; index[2] = 0; index[3] = 0; + activated_indices.push_back(index); + + index[0] = 9; index[1] = 7; index[2] = 0; index[3] = 0; + activated_indices.push_back(index); + + index[0] = 10; index[1] = 7; index[2] = 0; index[3] = 0; + activated_indices.push_back(index); + + std::vector< itk::Index<4U> >::const_iterator indexIter = activated_indices.begin(); + + mitk::ImagePixelWriteAccessor< unsigned char, 4> writeAccess(mask_image); + while (indexIter != activated_indices.end()) + { + writeAccess.SetPixelByIndex((*indexIter++), 1); + } } this->VerifyStatistics( ComputeStatistics( m_TestImage, mask_image ), 127.5, 127.5, 12.750); } void mitkImageStatisticsCalculatorTestSuite::TestRecomputeOnModifiedMask() { MITK_INFO << std::endl << "TestRecomputeOnModifiedMask:-----------------------------------------------------------------------------------"; mitk::Image::Pointer mask_image = mitk::ImageGenerator::GenerateImageFromReference( m_TestImage, 0 ); mitk::ImageStatisticsCalculator::Pointer statisticsCalculator = mitk::ImageStatisticsCalculator::New(); statisticsCalculator->SetInputImage( m_TestImage ); mitk::ImageMaskGenerator::Pointer imgMaskGen = mitk::ImageMaskGenerator::New(); imgMaskGen->SetImageMask(mask_image); statisticsCalculator->SetMask(imgMaskGen.GetPointer()); this->VerifyStatistics( statisticsCalculator->GetStatistics(), -21474836.480, -21474836.480, -21474836.480); // activate voxel in the mask image - itk::Index<3U> test_index = {{11, 8, 0}}; - mitk::ImagePixelWriteAccessor< unsigned char, 3> writeAccess( mask_image ); - writeAccess.SetPixelByIndex( test_index, 1); + if (mask_image->GetDimension() == 3) + { + itk::Index<3U> test_index = { { 11, 8, 0 } }; + mitk::ImagePixelWriteAccessor< unsigned char, 3> writeAccess(mask_image); + writeAccess.SetPixelByIndex(test_index, 1); + } + if (mask_image->GetDimension() == 4) + { + itk::Index<4U> test_index = { { 11, 8, 0, 0 } }; + mitk::ImagePixelWriteAccessor< unsigned char, 4> writeAccess(mask_image); + writeAccess.SetPixelByIndex(test_index, 1); + } + mask_image->Modified(); mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer stat = statisticsCalculator->GetStatistics(); this->VerifyStatistics( stat, 128.0, 0.0, 128.0); MITK_TEST_CONDITION( stat->GetN() == 1, "Calculated mask voxel count '" << stat->GetN() << "' is equal to the desired value '" << 1 << "'" ); } void mitkImageStatisticsCalculatorTestSuite::TestPic3DStatistics() { MITK_INFO << std::endl << "Test plain Pic3D:-----------------------------------------------------------------------------------"; long expected_N = 3211264; double expected_mean = -365.80015345982144; double expected_MPP = 111.80226129535752; double expected_median = -105.16000366210938; double expected_skewness = -0.26976612134147004; double expected_kurtosis = 1.4655017209571437; double expected_uniformity = 0.06087994379480554; double expected_UPP = 0.011227934437026977; double expected_variance = 224036.80150510342; double expected_standarddev = 473.32525973700518; double expected_min = -1023; double expected_max = 1361; double expected_RMS = 598.20276978323352; double expected_entropy = 4.6727423654570357; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 0; expected_minIndex[1] = 0; expected_minIndex[2] = 0; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 139; expected_maxIndex[1] = 182; expected_maxIndex[2] = 43; const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer result = ComputeStatisticsNew(m_Pic3DImage, 0); //std::cout << result->GetAsString(); VerifyStatistics(result, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestPic3DAxialPlanarFigureMaskStatistics() { MITK_INFO << std::endl << "Test Pic3D axial pf:-----------------------------------------------------------------------------------"; double expected_entropy = 5.6719817476387417; double expected_kurtosis = 5.8846935191205221; double expected_MPP = 230.43933685003768; double expected_max = 1206; double expected_mean = 182.30282131661443; double expected_median = 95.970001220703125; double expected_min = -156; long expected_N = 3190; double expected_RMS = 301.93844376702253; double expected_skewness = 1.6400489794326298; double expected_standarddev = 240.69172225993557; double expected_UPP = 0.024889790784288681; double expected_uniformity = 0.027579917650180332; double expected_variance = 57932.505164453964; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 156; expected_minIndex[1] = 133; expected_minIndex[2] = 24; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 125; expected_maxIndex[1] = 167; expected_maxIndex[2] = 24; mitk::PlanarFigureMaskGenerator::Pointer pfMaskGen = mitk::PlanarFigureMaskGenerator::New(); pfMaskGen->SetInputImage(m_Pic3DImage); pfMaskGen->SetPlanarFigure(m_Pic3DPlanarFigureAxial); const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer result = ComputeStatisticsNew(m_Pic3DImage, 0, pfMaskGen.GetPointer()); //std::cout << result->GetAsString(); VerifyStatistics(result, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestPic3DSagittalPlanarFigureMaskStatistics() { MITK_INFO << std::endl << "Test Pic3D sagittal pf:-----------------------------------------------------------------------------------"; double expected_entropy = 5.6051911962074286; double expected_kurtosis = 6.5814062739142338; double expected_MPP = 249.03202846975088; double expected_max = 1240; double expected_mean = 233.93602693602693; double expected_median = 174.9849853515625; double expected_min = -83; long expected_N = 1188; double expected_RMS = 332.03230188484594; double expected_skewness = 1.7489809015501814; double expected_standarddev = 235.62551813489128; double expected_UPP = 0.026837539253364174; double expected_uniformity = 0.027346982734188126; double expected_variance = 55519.384796335973; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 128; expected_minIndex[1] = 119; expected_minIndex[2] = 22; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 128; expected_maxIndex[1] = 167; expected_maxIndex[2] = 22; mitk::PlanarFigureMaskGenerator::Pointer pfMaskGen = mitk::PlanarFigureMaskGenerator::New(); pfMaskGen->SetInputImage(m_Pic3DImage); pfMaskGen->SetPlanarFigure(m_Pic3DPlanarFigureSagittal); const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer result = ComputeStatisticsNew(m_Pic3DImage, 0, pfMaskGen.GetPointer()); //std::cout << result->GetAsString(); VerifyStatistics(result, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestPic3DCoronalPlanarFigureMaskStatistics() { MITK_INFO << std::endl << "Test Pic3D coronal pf:-----------------------------------------------------------------------------------"; double expected_entropy = 6.0677398647867449; double expected_kurtosis = 1.6242929941303372; double expected_MPP = 76.649350649350652; double expected_max = 156; double expected_mean = -482.14807692307693; double expected_median = -660.07501220703125; double expected_min = -897; long expected_N = 520; double expected_RMS = 595.09446729069839; double expected_skewness = 0.51691492278851858; double expected_standarddev = 348.81321207686312; double expected_UPP = 0.0021560650887573964; double expected_uniformity = 0.020295857988165685; double expected_variance = 121670.6569193787; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 217; expected_minIndex[1] = 127; expected_minIndex[2] = 43; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 209; expected_maxIndex[1] = 127; expected_maxIndex[2] = 39; mitk::PlanarFigureMaskGenerator::Pointer pfMaskGen = mitk::PlanarFigureMaskGenerator::New(); pfMaskGen->SetInputImage(m_Pic3DImage); pfMaskGen->SetPlanarFigure(m_Pic3DPlanarFigureCoronal); const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer result = ComputeStatisticsNew(m_Pic3DImage, 0, pfMaskGen.GetPointer()); //std::cout << result->GetAsString(); VerifyStatistics(result, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestPic3DImageMaskStatistics_label1() { MITK_INFO << std::endl << "Test Pic3D image mask label 1 pf:-----------------------------------------------------------------------------------"; double expected_entropy = 5.695858251095868; double expected_kurtosis = 4.2728827997815717; double expected_MPP = 413.52408256880733; double expected_max = 1206; double expected_mean = 413.52408256880733; double expected_median = 324; double expected_min = 6; long expected_N = 872; double expected_RMS = 472.02024695145235; double expected_skewness = 1.3396074364415382; double expected_standarddev = 227.59821323493802; double expected_UPP = 0.029758648261930806; double expected_uniformity = 0.029758648261930806; double expected_variance = 51800.946667736309; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 135; expected_minIndex[1] = 158; expected_minIndex[2] = 24; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 125; expected_maxIndex[1] = 167; expected_maxIndex[2] = 24; mitk::ImageMaskGenerator::Pointer imgMaskGen = mitk::ImageMaskGenerator::New(); imgMaskGen->SetImageMask(m_Pic3DImageMask); imgMaskGen->SetInputImage(m_Pic3DImage); imgMaskGen->SetTimeStep(0); const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer result = ComputeStatisticsNew(m_Pic3DImage, 0, imgMaskGen.GetPointer(), nullptr, 1); //std::cout << result->GetAsString(); VerifyStatistics(result, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestPic3DImageMaskStatistics_label2() { MITK_INFO << std::endl << "Test Pic3D image mask label 2 pf:-----------------------------------------------------------------------------------"; double expected_entropy = 4.3685781901212764; double expected_kurtosis = 9.7999112757587934; double expected_MPP = -nan(""); double expected_max = -145; double expected_mean = -897.92833876221493; double expected_median = -969.16499900817871; double expected_min = -1008; long expected_N = 307; double expected_RMS = 913.01496468179471; double expected_skewness = 2.6658524648889736; double expected_standarddev = 165.29072623903585; double expected_UPP = 0; double expected_uniformity = 0.087544695434434425; double expected_variance = 27321.024180627897; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 170; expected_minIndex[1] = 60; expected_minIndex[2] = 24; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 173; expected_maxIndex[1] = 57; expected_maxIndex[2] = 24; mitk::ImageMaskGenerator::Pointer imgMaskGen = mitk::ImageMaskGenerator::New(); imgMaskGen->SetImageMask(m_Pic3DImageMask); imgMaskGen->SetInputImage(m_Pic3DImage); imgMaskGen->SetTimeStep(0); const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer result = ComputeStatisticsNew(m_Pic3DImage, 0, imgMaskGen.GetPointer(), nullptr, 2); //std::cout << result->GetAsString(); VerifyStatistics(result, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestPic3DIgnorePixelValueMaskStatistics() { MITK_INFO << std::endl << "Test Pic3D ignore zero pixels:-----------------------------------------------------------------------------------"; double expected_entropy = 4.671045011438645; double expected_kurtosis = 1.4638176488404484; double expected_MPP = 111.80226129535752; double expected_max = 1361; double expected_mean = -366.48547402877585; double expected_median = -105.16000366210938; double expected_min = -1023; long expected_N = 3205259; double expected_RMS = 598.76286909522139; double expected_skewness = -0.26648854845130782; double expected_standarddev = 473.50329537717545; double expected_UPP = 0.011270044547276429; double expected_uniformity = 0.061029773286547614; double expected_variance = 224205.37073304466; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 0; expected_minIndex[1] = 0; expected_minIndex[2] = 0; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 139; expected_maxIndex[1] = 182; expected_maxIndex[2] = 43; mitk::IgnorePixelMaskGenerator::Pointer ignPixelValMask = mitk::IgnorePixelMaskGenerator::New(); ignPixelValMask->SetInputImage(m_Pic3DImage); ignPixelValMask->SetIgnoredPixelValue(0); ignPixelValMask->SetTimeStep(0); const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer result = ComputeStatisticsNew(m_Pic3DImage, 0, ignPixelValMask.GetPointer()); //std::cout << result->GetAsString(); VerifyStatistics(result, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestPic3DSecondaryMaskStatistics() { MITK_INFO << std::endl << "Test Pic3D ignore zero pixels AND Image mask 2:-----------------------------------------------------------------------------------"; double expected_entropy = 5.9741637167320176; double expected_kurtosis = 3.490663358061596; double expected_MPP = 332.43534482758622; double expected_max = 1206; double expected_mean = 320.63333333333333; double expected_median = 265.06500244140625; double expected_min = -57; long expected_N = 720; double expected_RMS = 433.57749531594055; double expected_skewness = 1.1047775627624981; double expected_standarddev = 291.86248474238687; double expected_UPP = 0.020628858024691339; double expected_uniformity = 0.021377314814814797; double expected_variance = 85183.710000000006; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 116; expected_minIndex[1] = 170; expected_minIndex[2] = 24; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 125; expected_maxIndex[1] = 167; expected_maxIndex[2] = 24; mitk::IgnorePixelMaskGenerator::Pointer ignPixelValMask = mitk::IgnorePixelMaskGenerator::New(); ignPixelValMask->SetInputImage(m_Pic3DImage); ignPixelValMask->SetIgnoredPixelValue(0); ignPixelValMask->SetTimeStep(0); mitk::ImageMaskGenerator::Pointer imgMaskGen2 = mitk::ImageMaskGenerator::New(); imgMaskGen2->SetImageMask(m_Pic3DImageMask2); imgMaskGen2->SetInputImage(m_Pic3DImage); imgMaskGen2->SetTimeStep(0); const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer result = ComputeStatisticsNew(m_Pic3DImage, 0, imgMaskGen2.GetPointer(), ignPixelValMask.GetPointer()); //std::cout << result->GetAsString(); VerifyStatistics(result, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestUS4DCylStatistics_time1() { MITK_INFO << std::endl << "Test plain US4D timeStep1:-----------------------------------------------------------------------------------"; double expected_entropy = 4.8272774900452502; double expected_kurtosis = 6.1336513352934432; double expected_MPP = 53.395358640738536; double expected_max = 199; double expected_mean = 35.771298153622375; double expected_median = 20.894999504089355; double expected_min = 0; long expected_N = 3409920; double expected_RMS = 59.244523377028408; double expected_skewness = 1.8734292240015058; double expected_standarddev = 47.226346233600559; double expected_UPP = 0.12098731125004937; double expected_uniformity = 0.12098731125004937; double expected_variance = 2230.3277785759178; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 0; expected_minIndex[1] = 0; expected_minIndex[2] = 0; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 268; expected_maxIndex[1] = 101; expected_maxIndex[2] = 0; const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer result = ComputeStatisticsNew(m_US4DImage, 1); //std::cout << result->GetAsString(); VerifyStatistics(result, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestUS4DCylAxialPlanarFigureMaskStatistics_time1() { MITK_INFO << std::endl << "Test US4D axial pf timeStep1:-----------------------------------------------------------------------------------"; double expected_entropy = 6.218151288002292; double expected_kurtosis = 1.7322676370242023; double expected_MPP = 121.11663807890223; double expected_max = 199; double expected_mean = 121.11663807890223; double expected_median = 120.14999771118164; double expected_min = 9; long expected_N = 2332; double expected_RMS = 134.41895158590751; double expected_skewness = -0.1454808104597369; double expected_standarddev = 58.30278317472294; double expected_UPP = 0.021354765820606133; double expected_uniformity = 0.021354765820606133; double expected_variance = 3399.214525918756; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 129; expected_minIndex[1] = 131; expected_minIndex[2] = 19; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 126; expected_maxIndex[1] = 137; expected_maxIndex[2] = 19; mitk::PlanarFigureMaskGenerator::Pointer pfMaskGen = mitk::PlanarFigureMaskGenerator::New(); pfMaskGen->SetInputImage(m_US4DImage); pfMaskGen->SetPlanarFigure(m_US4DPlanarFigureAxial); const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer result = ComputeStatisticsNew(m_US4DImage, 1, pfMaskGen.GetPointer()); //std::cout << result->GetAsString(); VerifyStatistics(result, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestUS4DCylSagittalPlanarFigureMaskStatistics_time1() { MITK_INFO << std::endl << "Test US4D sagittal pf timeStep1:-----------------------------------------------------------------------------------"; double expected_entropy = 5.2003987046387508; double expected_kurtosis = 2.7574491062430142; double expected_MPP = 26.212534059945504; double expected_max = 59; double expected_mean = 26.176870748299319; double expected_median = 26.254999160766602; double expected_min = 0; long expected_N = 735; double expected_RMS = 28.084905283121476; double expected_skewness = 0.18245181360752327; double expected_standarddev = 10.175133541567705; double expected_UPP = 0.032921467906890628; double expected_uniformity = 0.032921467906890628; double expected_variance = 103.53334258873615; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 147; expected_minIndex[1] = 94; expected_minIndex[2] = 21; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 147; expected_maxIndex[1] = 77; expected_maxIndex[2] = 24; mitk::PlanarFigureMaskGenerator::Pointer pfMaskGen = mitk::PlanarFigureMaskGenerator::New(); pfMaskGen->SetInputImage(m_US4DImage); pfMaskGen->SetPlanarFigure(m_US4DPlanarFigureSagittal); const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer result = ComputeStatisticsNew(m_US4DImage, 1, pfMaskGen.GetPointer()); //std::cout << result->GetAsString(); VerifyStatistics(result, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestUS4DCylCoronalPlanarFigureMaskStatistics_time1() { MITK_INFO << std::endl << "Test US4D coronal pf timeStep1:-----------------------------------------------------------------------------------"; double expected_entropy = 5.8892941136639161; double expected_kurtosis = 4.6434920707409564; double expected_MPP = 55.486426346239433; double expected_max = 199; double expected_mean = 55.118479221927501; double expected_median = 36.815000534057617; double expected_min = 0; long expected_N = 2262; double expected_RMS = 71.98149752438627; double expected_skewness = 1.4988288344523237; double expected_standarddev = 46.29567187238105; double expected_UPP = 0.023286748110675673; double expected_uniformity = 0.023286748110675673; double expected_variance = 2143.2892341151742; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 214; expected_minIndex[1] = 169; expected_minIndex[2] = 10; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 99; expected_maxIndex[1] = 169; expected_maxIndex[2] = 17; mitk::PlanarFigureMaskGenerator::Pointer pfMaskGen = mitk::PlanarFigureMaskGenerator::New(); pfMaskGen->SetInputImage(m_US4DImage); pfMaskGen->SetPlanarFigure(m_US4DPlanarFigureCoronal); const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer result = ComputeStatisticsNew(m_US4DImage, 1, pfMaskGen.GetPointer()); //std::cout << result->GetAsString(); VerifyStatistics(result, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestUS4DCylImageMaskStatistics_time1_label_1() { MITK_INFO << std::endl << "Test US4D image mask time 1 label 1:-----------------------------------------------------------------------------------"; double expected_entropy = 5.0082903903398677; double expected_kurtosis = 3.6266994778237809; double expected_MPP = 169.58938547486034; double expected_max = 199; double expected_mean = 169.58938547486034; double expected_median = 187.44000244140625; double expected_min = 63; long expected_N = 716; double expected_RMS = 173.09843164831432; double expected_skewness = -1.2248969838579555; double expected_standarddev = 34.677188083311712; double expected_UPP = 0.076601073624418703; double expected_uniformity = 0.076601073624418703; double expected_variance = 1202.5073733653758; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 82; expected_minIndex[1] = 158; expected_minIndex[2] = 19; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 126; expected_maxIndex[1] = 140; expected_maxIndex[2] = 19; mitk::ImageMaskGenerator::Pointer imgMask1 = mitk::ImageMaskGenerator::New(); imgMask1->SetInputImage(m_US4DImage); imgMask1->SetImageMask(m_US4DImageMask); const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer result = ComputeStatisticsNew(m_US4DImage, 1, imgMask1.GetPointer(), nullptr, 1); //std::cout << result->GetAsString(); VerifyStatistics(result, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestUS4DCylImageMaskStatistics_time2_label_1() { MITK_INFO << std::endl << "Test US4D image mask time 2 label 1:-----------------------------------------------------------------------------------"; double expected_entropy = 5.1857604214916506; double expected_kurtosis = 3.0692303858330683; double expected_MPP = 167.97194163860831; double expected_max = 199; double expected_mean = 167.97194163860831; double expected_median = 184.39499664306641; double expected_min = 72; long expected_N = 891; double expected_RMS = 171.67986611998634; double expected_skewness = -1.1221651136259736; double expected_standarddev = 35.488071983870803; double expected_UPP = 0.063124070232188439; double expected_uniformity = 0.063124070232188439; double expected_variance = 1259.4032531323958; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 103; expected_minIndex[1] = 212; expected_minIndex[2] = 19; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 102; expected_maxIndex[1] = 168; expected_maxIndex[2] = 19; mitk::ImageMaskGenerator::Pointer imgMask1 = mitk::ImageMaskGenerator::New(); imgMask1->SetInputImage(m_US4DImage); imgMask1->SetImageMask(m_US4DImageMask); const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer result = ComputeStatisticsNew(m_US4DImage, 2, imgMask1.GetPointer(), nullptr, 1); //std::cout << result->GetAsString(); VerifyStatistics(result, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestUS4DCylImageMaskStatistics_time1_label_2() { MITK_INFO << std::endl << "Test US4D image mask time 1 label 2:-----------------------------------------------------------------------------------"; double expected_entropy = 5.0822234230119001; double expected_kurtosis = 2.4346603343623747; double expected_MPP = 20.733626373626375; double expected_max = 46; double expected_mean = 20.624836029733274; double expected_median = 20.010000228881836; double expected_min = 0; long expected_N = 2287; double expected_RMS = 22.508347574573804; double expected_skewness = 0.13837218490626488; double expected_standarddev = 9.0134260569684965; double expected_UPP = 0.034783970308787; double expected_uniformity = 0.034783970308787; double expected_variance = 81.241849284438644; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 178; expected_minIndex[1] = 76; expected_minIndex[2] = 19; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 198; expected_maxIndex[1] = 90; expected_maxIndex[2] = 19; mitk::ImageMaskGenerator::Pointer imgMask1 = mitk::ImageMaskGenerator::New(); imgMask1->SetInputImage(m_US4DImage); imgMask1->SetImageMask(m_US4DImageMask); const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer result = ComputeStatisticsNew(m_US4DImage, 1, imgMask1.GetPointer(), nullptr, 2); //std::cout << result->GetAsString(); VerifyStatistics(result, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestUS4DCylIgnorePixelValueMaskStatistics_time1() { MITK_INFO << std::endl << "Test US4D ignore zero pixels:-----------------------------------------------------------------------------------"; double expected_entropy = 5.8609813848087962; double expected_kurtosis = 4.7556214582883651; double expected_MPP = 53.395358640738536; double expected_max = 199; double expected_mean = 53.395358640738536; double expected_median = 35.649999618530273; double expected_min = 1; long expected_N = 2284417; double expected_RMS = 72.382339046507084; double expected_skewness = 1.588289859859108; double expected_standarddev = 48.868585834566694; double expected_UPP = 0.023927063695115193; double expected_uniformity = 0.023927063695115193; double expected_variance = 2388.1386814704128; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 187; expected_minIndex[1] = 19; expected_minIndex[2] = 0; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 268; expected_maxIndex[1] = 101; expected_maxIndex[2] = 0; mitk::IgnorePixelMaskGenerator::Pointer ignPixelValMask = mitk::IgnorePixelMaskGenerator::New(); ignPixelValMask->SetInputImage(m_US4DImage); ignPixelValMask->SetIgnoredPixelValue(0); ignPixelValMask->SetTimeStep(1); const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer result = ComputeStatisticsNew(m_US4DImage, 1, ignPixelValMask.GetPointer()); //std::cout << result->GetAsString(); VerifyStatistics(result, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestUS4DCylSecondaryMaskStatistics_time1() { MITK_INFO << std::endl << "Test US4d ignore zero pixels AND Image mask 2:-----------------------------------------------------------------------------------"; double expected_entropy = 4.9955858614274558; double expected_kurtosis = 17.471042803365179; double expected_MPP = 32.791403286978507; double expected_max = 199; double expected_mean = 32.791403286978507; double expected_median = 25.75; double expected_min = 1; long expected_N = 17402; double expected_RMS = 42.776697859745241; double expected_skewness = 3.3991813038552596; double expected_standarddev = 27.469433016621732; double expected_UPP = 0.043040554251756687; double expected_uniformity = 0.043040554251756687; double expected_variance = 754.56975025466807; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 177; expected_minIndex[1] = 27; expected_minIndex[2] = 36; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 109; expected_maxIndex[1] = 116; expected_maxIndex[2] = 36; mitk::IgnorePixelMaskGenerator::Pointer ignPixelValMask = mitk::IgnorePixelMaskGenerator::New(); ignPixelValMask->SetInputImage(m_US4DImage); ignPixelValMask->SetIgnoredPixelValue(0); mitk::ImageMaskGenerator::Pointer imgMaskGen2 = mitk::ImageMaskGenerator::New(); imgMaskGen2->SetImageMask(m_US4DImageMask2); imgMaskGen2->SetInputImage(m_US4DImage); const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer result = ComputeStatisticsNew(m_US4DImage, 1, imgMaskGen2.GetPointer(), ignPixelValMask.GetPointer()); //std::cout << result->GetAsString(); VerifyStatistics(result, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer mitkImageStatisticsCalculatorTestSuite::ComputeStatistics( mitk::Image::Pointer image, mitk::PlanarFigure::Pointer polygon ) { mitk::ImageStatisticsCalculator::Pointer statisticsCalculator = mitk::ImageStatisticsCalculator::New(); statisticsCalculator->SetInputImage( image ); statisticsCalculator->SetNBinsForHistogramStatistics(10); mitk::PlanarFigureMaskGenerator::Pointer planFigMaskGen = mitk::PlanarFigureMaskGenerator::New(); planFigMaskGen->SetInputImage(image); planFigMaskGen->SetPlanarFigure(polygon); statisticsCalculator->SetMask(planFigMaskGen.GetPointer()); try { return statisticsCalculator->GetStatistics(); } catch( ... ) { } return mitk::ImageStatisticsCalculator::StatisticsContainer::New(); } const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer mitkImageStatisticsCalculatorTestSuite::ComputeStatistics(mitk::Image::Pointer image, mitk::Image::Pointer image_mask ) { mitk::ImageStatisticsCalculator::Pointer statisticsCalculator = mitk::ImageStatisticsCalculator::New(); statisticsCalculator->SetInputImage(image); statisticsCalculator->SetNBinsForHistogramStatistics(10); mitk::ImageMaskGenerator::Pointer imgMaskGen = mitk::ImageMaskGenerator::New(); imgMaskGen->SetImageMask(image_mask); statisticsCalculator->SetMask(imgMaskGen.GetPointer()); return statisticsCalculator->GetStatistics(); } const mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer mitkImageStatisticsCalculatorTestSuite::ComputeStatisticsNew(mitk::Image::Pointer image, int timeStep, mitk::MaskGenerator::Pointer maskGen, mitk::MaskGenerator::Pointer secondardMaskGen, unsigned short label) { mitk::ImageStatisticsCalculator::Pointer imgStatCalc = mitk::ImageStatisticsCalculator::New(); imgStatCalc->SetInputImage(image); if (maskGen.IsNotNull()) { imgStatCalc->SetMask(maskGen.GetPointer()); if (secondardMaskGen.IsNotNull()) { imgStatCalc->SetSecondaryMask(secondardMaskGen.GetPointer()); } } return imgStatCalc->GetStatistics(timeStep, label); } void mitkImageStatisticsCalculatorTestSuite::VerifyStatistics(mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer stats, double testMean, double testSD, double testMedian) { int tmpMean = stats->GetMean() * 100; double calculatedMean = tmpMean / 100.0; MITK_TEST_CONDITION( calculatedMean == testMean, "Calculated mean grayvalue '" << calculatedMean << "' is equal to the desired value '" << testMean << "'" ); int tmpSD = stats->GetStd() * 100; double calculatedSD = tmpSD / 100.0; MITK_TEST_CONDITION( calculatedSD == testSD, "Calculated grayvalue sd '" << calculatedSD << "' is equal to the desired value '" << testSD <<"'" ); int tmpMedian = stats->GetMedian() * 100; double calculatedMedian = tmpMedian / 100.0; MITK_TEST_CONDITION( testMedian == calculatedMedian, "Calculated median grayvalue '" << calculatedMedian << "' is equal to the desired value '" << testMedian << "'"); } void mitkImageStatisticsCalculatorTestSuite::VerifyStatistics(mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer stats, long N, double mean, double MPP, double median, double skewness, double kurtosis, double uniformity, double UPP, double variance, double stdev, double min, double max, double RMS, double entropy, vnl_vector minIndex, vnl_vector maxIndex) { MITK_TEST_CONDITION(std::abs(stats->GetN() - N) < mitk::eps, "calculated N: " << stats->GetN() << " expected N: " << N); MITK_TEST_CONDITION(std::abs(stats->GetMean() - mean) < mitk::eps, "calculated mean: " << stats->GetMean() << " expected mean: " << mean); // in one test case MPP is None because the roi has no positive pixels if (!std::isnan(stats->GetMPP())) { MITK_TEST_CONDITION(std::abs(stats->GetMPP() - MPP) < mitk::eps, "calculated MPP: " << stats->GetMPP() << " expected MPP: " << MPP); } MITK_TEST_CONDITION(std::abs(stats->GetMedian() - median) < mitk::eps, "calculated median: " << stats->GetMedian() << " expected median: " << median); MITK_TEST_CONDITION(std::abs(stats->GetSkewness() - skewness) < mitk::eps, "calculated skewness: " << stats->GetSkewness() << " expected skewness: " << skewness); MITK_TEST_CONDITION(std::abs(stats->GetKurtosis() - kurtosis) < mitk::eps, "calculated kurtosis: " << stats->GetKurtosis() << " expected kurtosis: " << kurtosis); MITK_TEST_CONDITION(std::abs(stats->GetUniformity() - uniformity) < mitk::eps, "calculated uniformity: " << stats->GetUniformity() << " expected uniformity: " << uniformity); MITK_TEST_CONDITION(std::abs(stats->GetUPP() - UPP) < mitk::eps, "calculated UPP: " << stats->GetUPP() << " expected UPP: " << UPP); MITK_TEST_CONDITION(std::abs(stats->GetVariance() - variance) < mitk::eps, "calculated variance: " << stats->GetVariance() << " expected variance: " << variance); MITK_TEST_CONDITION(std::abs(stats->GetStd() - stdev) < mitk::eps, "calculated stdev: " << stats->GetStd() << " expected stdev: " << stdev); MITK_TEST_CONDITION(std::abs(stats->GetMin() - min) < mitk::eps, "calculated min: " << stats->GetMin() << " expected min: " << min); MITK_TEST_CONDITION(std::abs(stats->GetMax() - max) < mitk::eps, "calculated max: " << stats->GetMax() << " expected max: " << max); MITK_TEST_CONDITION(std::abs(stats->GetRMS() - RMS) < mitk::eps, "calculated RMS: " << stats->GetRMS() << " expected RMS: " << RMS); MITK_TEST_CONDITION(std::abs(stats->GetEntropy() - entropy) < mitk::eps, "calculated entropy: " << stats->GetEntropy() << " expected entropy: " << entropy); for (unsigned int i = 0; i < minIndex.size(); ++i) { MITK_TEST_CONDITION(std::abs(stats->GetMinIndex()[i] - minIndex[i]) < mitk::eps, "minIndex [" << i << "] = " << stats->GetMinIndex()[i] << " expected: " << minIndex[i]); } for (unsigned int i = 0; i < maxIndex.size(); ++i) { MITK_TEST_CONDITION(std::abs(stats->GetMaxIndex()[i] - maxIndex[i]) < mitk::eps, "maxIndex [" << i << "] = " << stats->GetMaxIndex()[i] << " expected: " << maxIndex[i]); } } void mitkImageStatisticsCalculatorTestSuite::TestUninitializedImage() { /***************************** * loading uninitialized image to datastorage ******************************/ MITK_INFO << std::endl << "Test uninitialized image: -----------------------------------------------------------------------------------"; MITK_TEST_FOR_EXCEPTION_BEGIN(mitk::Exception) mitk::Image::Pointer image = mitk::Image::New(); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(image); mitk::ImageStatisticsCalculator::Pointer is = mitk::ImageStatisticsCalculator::New(); is->GetStatistics(); MITK_TEST_FOR_EXCEPTION_END(mitk::Exception) } MITK_TEST_SUITE_REGISTRATION(mitkImageStatisticsCalculator) diff --git a/Modules/MapperExt/include/mitkVolumeMapperVtkSmart3D.h b/Modules/MapperExt/include/mitkVolumeMapperVtkSmart3D.h index 3403121248..679e11b169 100644 --- a/Modules/MapperExt/include/mitkVolumeMapperVtkSmart3D.h +++ b/Modules/MapperExt/include/mitkVolumeMapperVtkSmart3D.h @@ -1,75 +1,83 @@ /*=================================================================== 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 MITKVTKSMARTVOLUMEMAPPER_H_HEADER_INCLUDED #define MITKVTKSMARTVOLUMEMAPPER_H_HEADER_INCLUDED // MITK #include "MitkMapperExtExports.h" #include "mitkBaseRenderer.h" #include "mitkCommon.h" #include "mitkImage.h" #include "mitkVtkMapper.h" // VTK #include #include #include #include #include #include +#include + +class vtkRenderingOpenGL2ObjectFactory; +class vtkRenderingVolumeOpenGL2ObjectFactory; namespace mitk { //##Documentation //## @brief Vtk-based mapper for VolumeData //## //## @ingroup Mapper class MITKMAPPEREXT_EXPORT VolumeMapperVtkSmart3D : public VtkMapper { public: mitkClassMacro(VolumeMapperVtkSmart3D, VtkMapper); itkFactorylessNewMacro(Self) itkCloneMacro(Self) vtkProp *GetVtkProp(mitk::BaseRenderer *renderer) override; void ApplyProperties(vtkActor *actor, mitk::BaseRenderer *renderer) override; static void SetDefaultProperties(mitk::DataNode *node, mitk::BaseRenderer *renderer = nullptr, bool overwrite = false); protected: VolumeMapperVtkSmart3D(); ~VolumeMapperVtkSmart3D() override; void GenerateDataForRenderer(mitk::BaseRenderer *renderer) override; void createMapper(vtkImageData*); void createVolume(); void createVolumeProperty(); vtkImageData* GetInputImage(); vtkSmartPointer m_Volume; + vtkSmartPointer m_ImageChangeInformation; vtkSmartPointer m_SmartVolumeMapper; vtkSmartPointer m_VolumeProperty; + + vtkSmartPointer m_RenderingOpenGL2ObjectFactory; + vtkSmartPointer m_RenderingVolumeOpenGL2ObjectFactory; void UpdateTransferFunctions(mitk::BaseRenderer *renderer); void UpdateRenderMode(mitk::BaseRenderer *renderer); }; } // namespace mitk #endif /* MITKVTKSMARTVOLUMEMAPPER_H_HEADER_INCLUDED */ diff --git a/Modules/MapperExt/src/mitkVolumeMapperVtkSmart3D.cpp b/Modules/MapperExt/src/mitkVolumeMapperVtkSmart3D.cpp index fa505e97f4..698dd6129a 100644 --- a/Modules/MapperExt/src/mitkVolumeMapperVtkSmart3D.cpp +++ b/Modules/MapperExt/src/mitkVolumeMapperVtkSmart3D.cpp @@ -1,255 +1,262 @@ /*=================================================================== 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 "mitkVolumeMapperVtkSmart3D.h" #include "mitkTransferFunctionProperty.h" #include "mitkTransferFunctionInitializer.h" #include "mitkLevelWindowProperty.h" #include #include #include #include #include void mitk::VolumeMapperVtkSmart3D::GenerateDataForRenderer(mitk::BaseRenderer *renderer) { if (this->GetDataNode()->GetMTime() < this->GetMTime()) { return; } bool value; this->GetDataNode()->GetBoolProperty("volumerendering", value, renderer); if (!value) { m_Volume->VisibilityOff(); return; } else { m_Volume->VisibilityOn(); } UpdateTransferFunctions(renderer); UpdateRenderMode(renderer); this->Modified(); } vtkProp* mitk::VolumeMapperVtkSmart3D::GetVtkProp(mitk::BaseRenderer *) { if (!m_Volume->GetMapper()) { createMapper(GetInputImage()); createVolume(); createVolumeProperty(); } return m_Volume; } void mitk::VolumeMapperVtkSmart3D::ApplyProperties(vtkActor *, mitk::BaseRenderer *) { } void mitk::VolumeMapperVtkSmart3D::SetDefaultProperties(mitk::DataNode *node, mitk::BaseRenderer *renderer, bool overwrite) { // GPU_INFO << "SetDefaultProperties"; node->AddProperty("volumerendering", mitk::BoolProperty::New(false), renderer, overwrite); node->AddProperty("volumerendering.usemip", mitk::BoolProperty::New(false), renderer, overwrite); node->AddProperty("volumerendering.cpu.ambient", mitk::FloatProperty::New(0.10f), renderer, overwrite); node->AddProperty("volumerendering.cpu.diffuse", mitk::FloatProperty::New(0.50f), renderer, overwrite); node->AddProperty("volumerendering.cpu.specular", mitk::FloatProperty::New(0.40f), renderer, overwrite); node->AddProperty("volumerendering.cpu.specular.power", mitk::FloatProperty::New(16.0f), renderer, overwrite); node->AddProperty("volumerendering.usegpu", mitk::BoolProperty::New(false), renderer, overwrite); node->AddProperty("volumerendering.useray", mitk::BoolProperty::New(false), renderer, overwrite); node->AddProperty("volumerendering.gpu.ambient", mitk::FloatProperty::New(0.25f), renderer, overwrite); node->AddProperty("volumerendering.gpu.diffuse", mitk::FloatProperty::New(0.50f), renderer, overwrite); node->AddProperty("volumerendering.gpu.specular", mitk::FloatProperty::New(0.40f), renderer, overwrite); node->AddProperty("volumerendering.gpu.specular.power", mitk::FloatProperty::New(16.0f), renderer, overwrite); node->AddProperty("binary", mitk::BoolProperty::New(false), renderer, overwrite); mitk::Image::Pointer image = dynamic_cast(node->GetData()); if (image.IsNotNull() && image->IsInitialized()) { if ((overwrite) || (node->GetProperty("levelwindow", renderer) == nullptr)) { mitk::LevelWindowProperty::Pointer levWinProp = mitk::LevelWindowProperty::New(); mitk::LevelWindow levelwindow; levelwindow.SetAuto(image); levWinProp->SetLevelWindow(levelwindow); node->SetProperty("levelwindow", levWinProp, renderer); } if ((overwrite) || (node->GetProperty("TransferFunction", renderer) == nullptr)) { // add a default transfer function mitk::TransferFunction::Pointer tf = mitk::TransferFunction::New(); mitk::TransferFunctionInitializer::Pointer tfInit = mitk::TransferFunctionInitializer::New(tf); tfInit->SetTransferFunctionMode(0); node->SetProperty("TransferFunction", mitk::TransferFunctionProperty::New(tf.GetPointer())); } } Superclass::SetDefaultProperties(node, renderer, overwrite); } vtkImageData* mitk::VolumeMapperVtkSmart3D::GetInputImage() { - auto *input = const_cast(static_cast(this->GetDataNode()->GetData())); - vtkImageData* img = input->GetVtkImageData(this->GetTimestep()); - img->SetSpacing(1,1,1); - - return img; + auto input = dynamic_cast(this->GetDataNode()->GetData()); + return input->GetVtkImageData(this->GetTimestep()); } void mitk::VolumeMapperVtkSmart3D::createMapper(vtkImageData* imageData) { + Vector3D spacing; + FillVector3D(spacing, 1.0, 1.0, 1.0); + + m_ImageChangeInformation->SetInputData(imageData); + m_ImageChangeInformation->SetOutputSpacing(spacing.GetDataPointer()); + m_SmartVolumeMapper->SetBlendModeToComposite(); - m_SmartVolumeMapper->SetInputData(imageData); + m_SmartVolumeMapper->SetInputConnection(m_ImageChangeInformation->GetOutputPort()); } void mitk::VolumeMapperVtkSmart3D::createVolume() { m_Volume->VisibilityOff(); m_Volume->SetMapper(m_SmartVolumeMapper); m_Volume->SetProperty(m_VolumeProperty); } void mitk::VolumeMapperVtkSmart3D::createVolumeProperty() { m_VolumeProperty->ShadeOn(); m_VolumeProperty->SetInterpolationType(VTK_LINEAR_INTERPOLATION); } void mitk::VolumeMapperVtkSmart3D::UpdateTransferFunctions(mitk::BaseRenderer *renderer) { vtkSmartPointer opacityTransferFunction; vtkSmartPointer gradientTransferFunction; vtkSmartPointer colorTransferFunction; bool isBinary = false; this->GetDataNode()->GetBoolProperty("binary", isBinary, renderer); if (isBinary) { colorTransferFunction = vtkSmartPointer::New(); float rgb[3]; if (!GetDataNode()->GetColor(rgb, renderer)) rgb[0] = rgb[1] = rgb[2] = 1; colorTransferFunction->AddRGBPoint(0, rgb[0], rgb[1], rgb[2]); colorTransferFunction->Modified(); opacityTransferFunction = vtkSmartPointer::New(); gradientTransferFunction = vtkSmartPointer::New(); } else { auto *transferFunctionProp = dynamic_cast(this->GetDataNode()->GetProperty("TransferFunction", renderer)); if (transferFunctionProp) { opacityTransferFunction = transferFunctionProp->GetValue()->GetScalarOpacityFunction(); gradientTransferFunction = transferFunctionProp->GetValue()->GetGradientOpacityFunction(); colorTransferFunction = transferFunctionProp->GetValue()->GetColorTransferFunction(); } else { opacityTransferFunction = vtkSmartPointer::New(); gradientTransferFunction = vtkSmartPointer::New(); colorTransferFunction = vtkSmartPointer::New(); } } m_VolumeProperty->SetColor(colorTransferFunction); m_VolumeProperty->SetScalarOpacity(opacityTransferFunction); m_VolumeProperty->SetGradientOpacity(gradientTransferFunction); } void mitk::VolumeMapperVtkSmart3D::UpdateRenderMode(mitk::BaseRenderer *renderer) { bool usegpu = false; bool useray = false; bool usemip = false; this->GetDataNode()->GetBoolProperty("volumerendering.usegpu", usegpu); this->GetDataNode()->GetBoolProperty("volumerendering.useray", useray); this->GetDataNode()->GetBoolProperty("volumerendering.usemip", usemip); if (usegpu) m_SmartVolumeMapper->SetRequestedRenderModeToGPU(); else if (useray) m_SmartVolumeMapper->SetRequestedRenderModeToRayCast(); else m_SmartVolumeMapper->SetRequestedRenderModeToDefault(); int blendMode; if (this->GetDataNode()->GetIntProperty("volumerendering.blendmode", blendMode)) m_SmartVolumeMapper->SetBlendMode(blendMode); else if (usemip) m_SmartVolumeMapper->SetBlendMode(vtkSmartVolumeMapper::MAXIMUM_INTENSITY_BLEND); // shading parameter if (m_SmartVolumeMapper->GetRequestedRenderMode() == vtkSmartVolumeMapper::GPURenderMode) { float value = 0; if (this->GetDataNode()->GetFloatProperty("volumerendering.gpu.ambient", value, renderer)) m_VolumeProperty->SetAmbient(value); if (this->GetDataNode()->GetFloatProperty("volumerendering.gpu.diffuse", value, renderer)) m_VolumeProperty->SetDiffuse(value); if (this->GetDataNode()->GetFloatProperty("volumerendering.gpu.specular", value, renderer)) m_VolumeProperty->SetSpecular(value); if (this->GetDataNode()->GetFloatProperty("volumerendering.gpu.specular.power", value, renderer)) m_VolumeProperty->SetSpecularPower(value); } else { float value = 0; if (this->GetDataNode()->GetFloatProperty("volumerendering.cpu.ambient", value, renderer)) m_VolumeProperty->SetAmbient(value); if (this->GetDataNode()->GetFloatProperty("volumerendering.cpu.diffuse", value, renderer)) m_VolumeProperty->SetDiffuse(value); if (this->GetDataNode()->GetFloatProperty("volumerendering.cpu.specular", value, renderer)) m_VolumeProperty->SetSpecular(value); if (this->GetDataNode()->GetFloatProperty("volumerendering.cpu.specular.power", value, renderer)) m_VolumeProperty->SetSpecularPower(value); } } mitk::VolumeMapperVtkSmart3D::VolumeMapperVtkSmart3D() { - vtkObjectFactory::RegisterFactory(vtkRenderingOpenGL2ObjectFactory::New()); - vtkObjectFactory::RegisterFactory(vtkRenderingVolumeOpenGL2ObjectFactory::New()); + m_RenderingOpenGL2ObjectFactory = vtkSmartPointer::New(); + m_RenderingVolumeOpenGL2ObjectFactory = vtkSmartPointer::New(); + + vtkObjectFactory::RegisterFactory(m_RenderingOpenGL2ObjectFactory); + vtkObjectFactory::RegisterFactory(m_RenderingVolumeOpenGL2ObjectFactory); m_SmartVolumeMapper = vtkSmartPointer::New(); m_SmartVolumeMapper->SetBlendModeToComposite(); + m_ImageChangeInformation = vtkSmartPointer::New(); m_VolumeProperty = vtkSmartPointer::New(); m_Volume = vtkSmartPointer::New(); } mitk::VolumeMapperVtkSmart3D::~VolumeMapperVtkSmart3D() { } diff --git a/Modules/MatchPointRegistration/mitkMAPRegistrationWrapperObjectFactory.cpp b/Modules/MatchPointRegistration/mitkMAPRegistrationWrapperObjectFactory.cpp index dfe93f40fc..36dd9d4278 100644 --- a/Modules/MatchPointRegistration/mitkMAPRegistrationWrapperObjectFactory.cpp +++ b/Modules/MatchPointRegistration/mitkMAPRegistrationWrapperObjectFactory.cpp @@ -1,129 +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 "mitkMAPRegistrationWrapperObjectFactory.h" #include #include #include #include "mitkRegistrationWrapperMapper2D.h" #include "mitkRegistrationWrapperMapper3D.h" #include "mitkMAPRegistrationWrapper.h" typedef std::multimap MultimapType; mitk::MAPRegistrationWrapperObjectFactory::MAPRegistrationWrapperObjectFactory() : CoreObjectFactoryBase() { static bool alreadyDone = false; if (!alreadyDone) { - MITK_INFO << "MAPRegistrationWrapperObjectFactory c'tor" << std::endl; - alreadyDone = true; } } mitk::MAPRegistrationWrapperObjectFactory::~MAPRegistrationWrapperObjectFactory() { } mitk::Mapper::Pointer mitk::MAPRegistrationWrapperObjectFactory:: CreateMapper(mitk::DataNode* node, MapperSlotId slotId) { mitk::Mapper::Pointer newMapper=nullptr; if ( slotId == mitk::BaseRenderer::Standard2D ) { std::string classname("MAPRegistrationWrapper"); if(node->GetData() && classname.compare(node->GetData()->GetNameOfClass())==0) { newMapper = mitk::MITKRegistrationWrapperMapper2D::New(); newMapper->SetDataNode(node); } } else if ( slotId == mitk::BaseRenderer::Standard3D ) { std::string classname("MAPRegistrationWrapper"); if(node->GetData() && classname.compare(node->GetData()->GetNameOfClass())==0) { newMapper = mitk::MITKRegistrationWrapperMapper3D::New(); newMapper->SetDataNode(node); } } return newMapper; }; void mitk::MAPRegistrationWrapperObjectFactory::SetDefaultProperties(mitk::DataNode* node) { if(node==nullptr) return; mitk::DataNode::Pointer nodePointer = node; if(node->GetData() ==nullptr) return; if( dynamic_cast(node->GetData())!=nullptr ) { mitk::MITKRegistrationWrapperMapperBase::SetDefaultProperties(node); } } const char* mitk::MAPRegistrationWrapperObjectFactory::GetFileExtensions() { std::string fileExtension; this->CreateFileExtensions(m_FileExtensionsMap, fileExtension); return fileExtension.c_str(); }; mitk::CoreObjectFactoryBase::MultimapType mitk::MAPRegistrationWrapperObjectFactory::GetFileExtensionsMap() { return m_FileExtensionsMap; } const char* mitk::MAPRegistrationWrapperObjectFactory::GetSaveFileExtensions() { std::string fileExtension; this->CreateFileExtensions(m_SaveFileExtensionsMap, fileExtension); return fileExtension.c_str(); } mitk::CoreObjectFactoryBase::MultimapType mitk::MAPRegistrationWrapperObjectFactory::GetSaveFileExtensionsMap() { return m_SaveFileExtensionsMap; } struct RegisterMAPRegistrationWrapperObjectFactoryHelper{ RegisterMAPRegistrationWrapperObjectFactoryHelper() : m_Factory( mitk::MAPRegistrationWrapperObjectFactory::New() ) { mitk::CoreObjectFactory::GetInstance()->RegisterExtraFactory( m_Factory ); } ~RegisterMAPRegistrationWrapperObjectFactoryHelper() { mitk::CoreObjectFactory::GetInstance()->UnRegisterExtraFactory( m_Factory ); } mitk::MAPRegistrationWrapperObjectFactory::Pointer m_Factory; }; static RegisterMAPRegistrationWrapperObjectFactoryHelper registerMITKRegistrationWrapperIOFactoryHelper; diff --git a/Modules/MatchPointRegistration/mitkRegEvaluationObjectFactory.cpp b/Modules/MatchPointRegistration/mitkRegEvaluationObjectFactory.cpp index 1faecb49bb..5002964542 100644 --- a/Modules/MatchPointRegistration/mitkRegEvaluationObjectFactory.cpp +++ b/Modules/MatchPointRegistration/mitkRegEvaluationObjectFactory.cpp @@ -1,109 +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. ===================================================================*/ #include "mitkRegEvaluationObjectFactory.h" #include #include #include #include "mitkRegEvaluationMapper2D.h" typedef std::multimap MultimapType; mitk::RegEvaluationObjectFactory::RegEvaluationObjectFactory() : CoreObjectFactoryBase() { static bool alreadyDone = false; if (!alreadyDone) { - MITK_INFO << "RegEvaluationObjectFactory c'tor" << std::endl; - alreadyDone = true; } } mitk::RegEvaluationObjectFactory::~RegEvaluationObjectFactory() { } mitk::Mapper::Pointer mitk::RegEvaluationObjectFactory:: CreateMapper(mitk::DataNode* node, MapperSlotId slotId) { mitk::Mapper::Pointer newMapper = nullptr; if ( slotId == mitk::BaseRenderer::Standard2D ) { std::string classname("RegEvaluationObject"); if(node->GetData() && classname.compare(node->GetData()->GetNameOfClass())==0) { newMapper = mitk::RegEvaluationMapper2D::New(); newMapper->SetDataNode(node); } } return newMapper; }; void mitk::RegEvaluationObjectFactory::SetDefaultProperties(mitk::DataNode*) { } const char* mitk::RegEvaluationObjectFactory::GetFileExtensions() { //return empty (dummy) extension string return m_FileExtensions.c_str(); }; mitk::CoreObjectFactoryBase::MultimapType mitk::RegEvaluationObjectFactory::GetFileExtensionsMap() { return mitk::CoreObjectFactoryBase::MultimapType(); } const char* mitk::RegEvaluationObjectFactory::GetSaveFileExtensions() { //return empty (dummy) extension string return m_FileExtensions.c_str(); } mitk::CoreObjectFactoryBase::MultimapType mitk::RegEvaluationObjectFactory::GetSaveFileExtensionsMap() { return mitk::CoreObjectFactoryBase::MultimapType(); } void mitk::RegEvaluationObjectFactory::RegisterIOFactories() { } struct RegisterRegEvaluationObjectFactoryHelper{ RegisterRegEvaluationObjectFactoryHelper() : m_Factory( mitk::RegEvaluationObjectFactory::New() ) { mitk::CoreObjectFactory::GetInstance()->RegisterExtraFactory( m_Factory ); } ~RegisterRegEvaluationObjectFactoryHelper() { mitk::CoreObjectFactory::GetInstance()->UnRegisterExtraFactory( m_Factory ); } mitk::RegEvaluationObjectFactory::Pointer m_Factory; }; static RegisterRegEvaluationObjectFactoryHelper registerMITKRegistrationWrapperIOFactoryHelper; diff --git a/Modules/OpenCL/files.cmake b/Modules/OpenCL/files.cmake index 799077854e..c1f158a404 100644 --- a/Modules/OpenCL/files.cmake +++ b/Modules/OpenCL/files.cmake @@ -1,23 +1,26 @@ set(CPP_FILES # helper classes mitkOclUtils.cpp mitkOclResourceServiceImpl_Private.cpp mitkOclImageFormats.cpp # module activator mitkOpenCLActivator.cpp # base data and filter objects mitkOclBaseData.cpp mitkOclImage.cpp + mitkOclDataSet.cpp mitkOclFilter.cpp mitkOclImageFilter.cpp + mitkOclDataSetFilter.cpp mitkOclImageToImageFilter.cpp + mitkOclDataSetToDataSetFilter.cpp # own filter implementations mitkOclBinaryThresholdImageFilter.cpp ) set(RESOURCE_FILES BinaryThresholdFilter.cl ) diff --git a/Modules/OpenCL/mitkOclDataSet.cpp b/Modules/OpenCL/mitkOclDataSet.cpp new file mode 100644 index 0000000000..953c0d68b1 --- /dev/null +++ b/Modules/OpenCL/mitkOclDataSet.cpp @@ -0,0 +1,176 @@ +/*=================================================================== + +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 "mitkOclDataSet.h" +#include "mitkCommon.h" +#include "mitkLogMacros.h" + +#include "mitkOclUtils.h" + +#include + +//#define SHOW_MEM_INFO + +mitk::OclDataSet::OclDataSet() : m_gpuBuffer(nullptr), m_context(nullptr), m_bufferSize(0), m_gpuModified(false), m_cpuModified(false), + m_Data(nullptr), m_BpE(1) +{ +} + +mitk::OclDataSet::~OclDataSet() +{ + MITK_DEBUG << "OclDataSet Destructor"; + + //release GMEM Image buffer + if (m_gpuBuffer) clReleaseMemObject(m_gpuBuffer); +} + + +cl_mem mitk::OclDataSet::CreateGPUBuffer() +{ + MITK_DEBUG << "InitializeGPUBuffer call with: BPE=" << m_BpE; + + us::ServiceReference ref = GetModuleContext()->GetServiceReference(); + OclResourceService* resources = GetModuleContext()->GetService(ref); + + m_context = resources->GetContext(); + + int clErr; + if (m_gpuBuffer) clReleaseMemObject(m_gpuBuffer); + + m_gpuBuffer = clCreateBuffer(m_context, CL_MEM_READ_WRITE, m_bufferSize * (size_t)m_BpE, nullptr, &clErr); + + #ifdef SHOW_MEM_INFO + MITK_INFO << "Created GPU Buffer Object of size: " << (size_t)m_BpE * m_bufferSize << " Bytes"; + #endif + + CHECK_OCL_ERR(clErr); + + if (clErr != CL_SUCCESS) + mitkThrow() << "openCL Error when creating Buffer"; + + return m_gpuBuffer; +} + +bool mitk::OclDataSet::IsModified(int _type) +{ + if (_type) return m_cpuModified; + else return m_gpuModified; +} + +void mitk::OclDataSet::Modified(int _type) +{ + // defines... GPU: 0, CPU: 1 + m_cpuModified = _type; + m_gpuModified = !_type; +} + +int mitk::OclDataSet::TransferDataToGPU(cl_command_queue gpuComQueue) +{ + cl_int clErr = 0; + + // check whether an image present + if (m_Data == nullptr){ + MITK_ERROR("ocl.DataSet") << "(mitk) No data present!\n"; + return -1; + } + + // there is a need for copy only if RAM-Data newer then GMEM data + if (m_cpuModified) + { + //check the buffer + if(m_gpuBuffer == nullptr) + { + CreateGPUBuffer(); + } + + if (m_gpuBuffer != nullptr) + { + clErr = clEnqueueWriteBuffer(gpuComQueue, m_gpuBuffer, CL_TRUE, 0, m_bufferSize * (size_t)m_BpE, m_Data, 0, NULL, NULL); + MITK_DEBUG << "Wrote Data to GPU Buffer Object."; + + CHECK_OCL_ERR(clErr); + m_gpuModified = true; + + if (clErr != CL_SUCCESS) + mitkThrow() << "openCL Error when writing Buffer"; + } + else + { + MITK_ERROR << "No GPU buffer present!"; + } + } + + return clErr; +} + +cl_mem mitk::OclDataSet::GetGPUBuffer() +{ + // query image object info only if already initialized + if( this->m_gpuBuffer ) + { + #ifdef SHOW_MEM_INFO + cl_int clErr = 0; + // clGetMemObjectInfo() + cl_mem_object_type memInfo; + clErr = clGetMemObjectInfo(this->m_gpuBuffer, CL_MEM_TYPE, sizeof(cl_mem_object_type), &memInfo, nullptr ); + CHECK_OCL_ERR(clErr); + MITK_DEBUG << "Querying info for object, recieving: " << memInfo; + #endif + } + + return m_gpuBuffer; +} + +void* mitk::OclDataSet::TransferDataToCPU(cl_command_queue gpuComQueue) +{ + cl_int clErr = 0; + + // if image created on GPU, needs to create mitk::Image + if( m_gpuBuffer == nullptr ){ + MITK_ERROR("ocl.DataSet") << "(mitk) No buffer present!\n"; + return nullptr; + } + + // check buffersize + char* data = new char[m_bufferSize * (size_t)m_BpE]; + + // debug info + #ifdef SHOW_MEM_INFO + oclPrintMemObjectInfo( m_gpuBuffer ); + #endif + + clErr = clEnqueueReadBuffer( gpuComQueue, m_gpuBuffer, CL_TRUE, 0, m_bufferSize * (size_t)m_BpE, data ,0, nullptr, nullptr); + CHECK_OCL_ERR(clErr); + + if(clErr != CL_SUCCESS) + mitkThrow() << "openCL Error when reading Output Buffer"; + + clFlush( gpuComQueue ); + // the cpu data is same as gpu + this->m_gpuModified = false; + + return (void*) data; +} + +void mitk::OclDataSet::SetBufferSize(size_t size) +{ + m_bufferSize = size; +} + +void mitk::OclDataSet::SetBpE(unsigned short BpE) +{ + m_BpE = BpE; +} diff --git a/Modules/OpenCL/mitkOclDataSet.h b/Modules/OpenCL/mitkOclDataSet.h new file mode 100644 index 0000000000..773510e47c --- /dev/null +++ b/Modules/OpenCL/mitkOclDataSet.h @@ -0,0 +1,134 @@ +/*=================================================================== + +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 __mitkOclDataSet_h +#define __mitkOclDataSet_h + +#define GPU_DATA 0 +#define CPU_DATA 1 + +#include +#include "MitkOpenCLExports.h" + +#include "mitkOclBaseData.h" +#include "mitkOpenCLActivator.h" + +#include + +namespace mitk { + +/*! + * \brief Class implementing processing of arbitrary data sets for GPU Image Processing + * + * The class holds a pointer to the data stored in RAM and performs an + * on-demand-copy to the graphics memory. It is the basic data structure for all + * mitk::oclDataSetToDataSetFilter classes + */ +class MITKOPENCL_EXPORT OclDataSet : public OclBaseData +{ +public: + mitkClassMacro(OclDataSet, OclBaseData); + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + + /*! \brief Copies the RAM-stored data to GMEM */ + virtual int TransferDataToGPU(cl_command_queue); + + /*! \brief Copies the in GMEM stored data to RAM */ + virtual void* TransferDataToCPU(cl_command_queue); + + /*! \brief Returns the pointer to the referenced data */ + void* GetData() + { + return m_Data; + } + + /** Returns the pointer to the GPU buffer */ + cl_mem GetGPUBuffer(); + + /** Create the GPU buffer for image + * + */ + cl_mem CreateGPUBuffer(); + + /** \brief Returns the status of the image buffer + * + * @param _type The flag to specify the buffer type ( GPU / CPU ) + */ + bool IsModified(int _type); + + using OclBaseData::Modified; + + /** \brief Set the modified flag for one of the buffers + * + * @param _type The flag to specify the buffer type ( GPU / CPU ) + */ + void Modified(int _type); + + /** \brief Initialze the OclDataSet with data. */ + void SetData(void* data) + { + this->m_cpuModified = true; + this->m_gpuModified = false; + m_Data = data; + } + + /*! \brief returns the amount of elements in the DataSet */ + size_t GetBufferSize() const + { + return this->m_bufferSize; + } + + short GetBytesPerElement() const + { + return this->m_BpE; + } + + /** @brief Set the amount of elements in buffer*/ + void SetBufferSize(size_t size); + + /** @brief Set the DataSet memory Size per Element in Bytes*/ + void SetBpE(unsigned short BpE); + +protected: + /*! \brief Constructor */ + OclDataSet(); + + /** @brief Destructor */ + virtual ~OclDataSet(); + + /*! GMEM Image buffer */ + cl_mem m_gpuBuffer; + + /*! GPU Context the Buffer was created in, needed for access */ + cl_context m_context; + +private: + /*! GMEM Buffer Size in elements*/ + size_t m_bufferSize; + + bool m_gpuModified; + bool m_cpuModified; + + /*! Reference to the data */ + void* m_Data; + + /*! Bytes per Element in Buffer*/ + unsigned short m_BpE; +}; + +} +#endif //__mitkOclDataSet_h diff --git a/Modules/OpenCL/mitkOclDataSetFilter.cpp b/Modules/OpenCL/mitkOclDataSetFilter.cpp new file mode 100644 index 0000000000..f30719b5ae --- /dev/null +++ b/Modules/OpenCL/mitkOclDataSetFilter.cpp @@ -0,0 +1,55 @@ +/*=================================================================== + +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 "mitkOclDataSetFilter.h" +#include "mitkOclFilter.h" +#include "mitkOclDataSet.h" +#include "mitkImageReadAccessor.h" + +mitk::OclDataSetFilter::OclDataSetFilter() +{ +} + +mitk::OclDataSetFilter::~OclDataSetFilter() +{ +} + +void mitk::OclDataSetFilter::SetInput(mitk::OclDataSet::Pointer DataSet) +{ + m_Input = DataSet; +} + +void mitk::OclDataSetFilter::SetInput(void* DataSet, unsigned int size, unsigned int BpE) +{ + m_Input = mitk::OclDataSet::New(); + m_Input->SetData(DataSet); + m_Input->SetBufferSize(size); + m_Input->SetBpE(BpE); + m_CurrentSize = BpE; +} + +void mitk::OclDataSetFilter::SetInput(mitk::Image::Pointer image) +{ + m_Input = mitk::OclDataSet::New(); + mitk::ImageReadAccessor reader(image); + + m_Input->SetData(const_cast(reader.GetData())); + m_CurrentSize = (unsigned int)(image->GetPixelType().GetBitsPerComponent() / 8); + unsigned int elements = image->GetDimension(0) * image->GetDimension(1) * image->GetDimension(2); + + m_Input->SetBufferSize(elements); + m_Input->SetBpE(m_CurrentSize); +} \ No newline at end of file diff --git a/Modules/OpenCL/mitkOclDataSetFilter.h b/Modules/OpenCL/mitkOclDataSetFilter.h new file mode 100644 index 0000000000..881291bbd0 --- /dev/null +++ b/Modules/OpenCL/mitkOclDataSetFilter.h @@ -0,0 +1,69 @@ +/*=================================================================== + +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 __mitkOclDataSetFilter_h +#define __mitkOclDataSetFilter_h + +#include "mitkOclFilter.h" +#include "mitkOclDataSet.h" + +#define FILTER_UCHAR 0 +#define FILTER_SHORT 1 + +namespace mitk +{ +class OclFilter; +class OclDataSetFilter; + + /** + * \brief The OclDataSetFilter is the topmost class for all filter which take DataSets as input. + * + * The input DataSet can be intialized via an oclDataSet or a pointer to the data + * This makes it possible to create a filter pipeline of GPU-based filters + * and to bind this part into the CPU (ITK) filter pipeline. + */ +class MITKOPENCL_EXPORT OclDataSetFilter: public OclFilter +{ +public: + /** + * @brief SetInput SetInput Set the input DataSet (as mitk::OclDataSet). + * @param DataSet The DataSet in mitk::OclDataSet. + */ + void SetInput(mitk::OclDataSet::Pointer DataSet); + + /** + * @brief SetInput Set the input DataSet (as a pointer to the data). + * @param DataSet The DataSet in mitk::OclDataSet. + */ + void SetInput(void* DataSet, unsigned int size, unsigned int BpE); + + /** + * @brief SetInput Set the input DataSet (as mitk::Image). + * @param DataSet The DataSet in mitk::OclDataSet. + */ + void SetInput(mitk::Image::Pointer image); + +protected: + OclDataSetFilter(); + + virtual ~OclDataSetFilter(); + + /** The input DataSet */ + mitk::OclDataSet::Pointer m_Input; + unsigned int m_CurrentSize; +}; +} +#endif // __mitkOclDataSetFilter_h diff --git a/Modules/OpenCL/mitkOclDataSetToDataSetFilter.cpp b/Modules/OpenCL/mitkOclDataSetToDataSetFilter.cpp new file mode 100644 index 0000000000..2cf7acab5d --- /dev/null +++ b/Modules/OpenCL/mitkOclDataSetToDataSetFilter.cpp @@ -0,0 +1,128 @@ +/*=================================================================== + +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 "mitkOclDataSetToDataSetFilter.h" +#include "mitkOclDataSet.h" + +#include "mitkException.h" + +mitk::OclDataSetToDataSetFilter::OclDataSetToDataSetFilter() +{ + m_Output = mitk::OclDataSet::New(); +} + + +mitk::OclDataSetToDataSetFilter::~OclDataSetToDataSetFilter() +{ +} + +mitk::OclDataSet::Pointer mitk::OclDataSetToDataSetFilter::GetGPUOutput() +{ + return this->m_Output; +} + +void* mitk::OclDataSetToDataSetFilter::GetOutput() +{ + void* pData = m_Output->TransferDataToCPU(m_CommandQue); + return pData; +} + +int mitk::OclDataSetToDataSetFilter::GetBytesPerElem() +{ + return this->m_CurrentSizeOutput; +} + +bool mitk::OclDataSetToDataSetFilter::InitExec(cl_kernel ckKernel, unsigned int* dimensions, size_t outputDataSize, unsigned int outputBpE) +{ + cl_int clErr = 0; + + if (m_Input.IsNull()) + mitkThrow() << "Input DataSet is null."; + + // get DataSet size once + const unsigned int uiDataSetWidth = dimensions[0]; + const unsigned int uiDataSetHeight = dimensions[1]; + const unsigned int uiDataSetDepth = dimensions[2]; + + // compute work sizes + this->SetWorkingSize(8, uiDataSetWidth, 8, uiDataSetHeight, 8, uiDataSetDepth); + + cl_mem clBuffIn = m_Input->GetGPUBuffer(); + cl_mem clBuffOut = m_Output->GetGPUBuffer(); + + if (!clBuffIn) + { + if (m_Input->TransferDataToGPU(m_CommandQue) != CL_SUCCESS) + { + mitkThrow() << "Could not create / initialize gpu DataSet."; + } + + clBuffIn = m_Input->GetGPUBuffer(); + } + + // output DataSet not initialized or output buffer size changed + if (!clBuffOut || (size_t)m_Output->GetBufferSize() != outputDataSize) + { + MITK_DEBUG << "Create GPU DataSet call " << uiDataSetWidth << "x" << uiDataSetHeight << "x" << uiDataSetDepth; + m_Output->SetBpE(outputBpE); + m_Output->SetBufferSize(outputDataSize); + clBuffOut = m_Output->CreateGPUBuffer(); + m_CurrentSizeOutput = outputBpE; + } + + clErr = 0; + clErr = clSetKernelArg(ckKernel, 0, sizeof(cl_mem), &clBuffIn); + clErr |= clSetKernelArg(ckKernel, 1, sizeof(cl_mem), &clBuffOut); + CHECK_OCL_ERR(clErr); + + if (clErr != CL_SUCCESS) + mitkThrow() << "OpenCL Part initialization failed with " << GetOclErrorAsString(clErr); + + return(clErr == CL_SUCCESS); +} + +bool mitk::OclDataSetToDataSetFilter::InitExecNoInput(cl_kernel ckKernel, unsigned int* dimensions, size_t outputDataSize, unsigned int outputBpE) +{ + cl_int clErr = 0; + + // get DataSet size once + const unsigned int uiDataSetWidth = dimensions[0]; + const unsigned int uiDataSetHeight = dimensions[1]; + const unsigned int uiDataSetDepth = dimensions[2]; + + // compute work sizes + this->SetWorkingSize(8, uiDataSetWidth, 8, uiDataSetHeight, 8, uiDataSetDepth); + + cl_mem clBuffOut = m_Output->GetGPUBuffer(); + + // output DataSet not initialized or output buffer size changed + if (!clBuffOut || (size_t)m_Output->GetBufferSize() != outputDataSize) + { + MITK_DEBUG << "Create GPU DataSet call " << uiDataSetWidth << "x" << uiDataSetHeight << "x" << uiDataSetDepth; + m_Output->SetBpE(outputBpE); + m_Output->SetBufferSize(outputDataSize); + clBuffOut = m_Output->CreateGPUBuffer(); + m_CurrentSizeOutput = outputBpE; + } + + clErr = clSetKernelArg(ckKernel, 0, sizeof(cl_mem), &clBuffOut); + CHECK_OCL_ERR(clErr); + + if (clErr != CL_SUCCESS) + mitkThrow() << "OpenCL Part initialization failed with " << GetOclErrorAsString(clErr); + + return(clErr == CL_SUCCESS); +} \ No newline at end of file diff --git a/Modules/OpenCL/mitkOclDataSetToDataSetFilter.h b/Modules/OpenCL/mitkOclDataSetToDataSetFilter.h new file mode 100644 index 0000000000..0891e8b876 --- /dev/null +++ b/Modules/OpenCL/mitkOclDataSetToDataSetFilter.h @@ -0,0 +1,81 @@ +/*=================================================================== + +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 __mitkOclDataSetToDataSetFilter_h +#define __mitkOclDataSetToDataSetFilter_h + +#include "mitkOclDataSetFilter.h" + +namespace mitk +{ +class OclDataSetFilter; +class OclDataSetToDataSetFilter; + +/** @class OclDataSetToDataSetFilter + * @brief The OclDataSetToDataSetFilter is the base class for all OpenCL DataSet filter generating DataSets. + */ +class MITKOPENCL_EXPORT OclDataSetToDataSetFilter: public OclDataSetFilter +{ +public: + /*! + * \brief Returns an pointer to the filtered data. + */ + void* GetOutput(); + + /*! + * \brief Returns a pointer to the graphics memory. + * + * Use this method when executing two and more filters on the GPU for fast access. + * This method does not copy the data to RAM. It returns only a pointer. + */ + mitk::OclDataSet::Pointer GetGPUOutput(); + +protected: + /** + * @brief OclDataSetToDataSetFilter Default constructor. + */ + OclDataSetToDataSetFilter(); + + /** @brief Destructor */ + virtual ~OclDataSetToDataSetFilter(); + + /** Output DataSet */ + mitk::OclDataSet::Pointer m_Output; + + /** @brief (Virtual) method Update() to be implemented in derived classes. */ + virtual void Update() = 0; + + /** + * @brief InitExec Initialize the execution + * @param ckKernel The GPU kernel. + * @throws mitk::Exception if something goes wrong. + * @return True for success. + */ + bool InitExec(cl_kernel ckKernel, unsigned int* dimensions, size_t outputDataSize, unsigned int outputBpE); + + bool InitExecNoInput(cl_kernel ckKernel, unsigned int* dimensions, size_t outputDataSize, unsigned int outputBpE); + + /** @brief Get the memory size needed for each element */ + virtual int GetBytesPerElem(); + + unsigned int m_CurrentSizeOutput; + +private: + /** Block dimensions */ + unsigned int m_BlockDims[3]; +}; +} +#endif // __mitkOclDataSetToDataSetFilter_h diff --git a/Modules/OpenCL/mitkOclFilter.cpp b/Modules/OpenCL/mitkOclFilter.cpp index 5312e59117..a3fb6c9ebd 100644 --- a/Modules/OpenCL/mitkOclFilter.cpp +++ b/Modules/OpenCL/mitkOclFilter.cpp @@ -1,248 +1,355 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ //Ocl #include "mitkOclFilter.h" #include "mitkOclUtils.h" #include "mitkOpenCLActivator.h" + //Mitk #include #include //usService #include "usServiceReference.h" #include #include #include #include #include #include +//standard library +#include + mitk::OclFilter::OclFilter() : m_ClCompilerFlags(""), m_ClProgram(nullptr), m_CommandQue(nullptr), m_FilterID("mitkOclFilter"), m_Preambel(" "), m_Initialized(false) { } mitk::OclFilter::OclFilter(const char* filename) : m_ClCompilerFlags(""), m_ClProgram(nullptr), m_CommandQue(nullptr), m_FilterID(filename), m_Preambel(" "), m_Initialized(false) { m_ClFiles.push_back(filename); } mitk::OclFilter::~OclFilter() { MITK_DEBUG << "OclFilter Destructor"; // release program if (m_ClProgram) { us::ServiceReference ref = GetModuleContext()->GetServiceReference(); OclResourceService* resources = GetModuleContext()->GetService(ref); // remove program from storage resources->RemoveProgram(m_FilterID); } } bool mitk::OclFilter::ExecuteKernel( cl_kernel kernel, unsigned int workSizeDim ) { cl_int clErr = 0; clErr = clEnqueueNDRangeKernel( this->m_CommandQue, kernel, workSizeDim, nullptr, this->m_GlobalWorkSize, m_LocalWorkSize, 0, nullptr, nullptr); CHECK_OCL_ERR( clErr ); return ( clErr == CL_SUCCESS ); } +bool mitk::OclFilter::ExecuteKernelChunks( cl_kernel kernel, unsigned int workSizeDim, size_t* chunksDim ) +{ + size_t offset[3] ={0, 0, 0}; + cl_int clErr = 0; + + if(workSizeDim == 2) + { + for(offset[0] = 0; offset[0] < m_GlobalWorkSize[0]; offset[0] += chunksDim[0]) + { + for(offset[1] = 0; offset[1] < m_GlobalWorkSize[1]; offset[1] += chunksDim[1]) + { + clErr |= clEnqueueNDRangeKernel(this->m_CommandQue, kernel, workSizeDim, + offset, chunksDim, m_LocalWorkSize, 0, nullptr, nullptr); + } + } + } + else if(workSizeDim == 3) + { + for(offset[0] = 0; offset[0] < m_GlobalWorkSize[0]; offset[0] += chunksDim[0]) + { + for(offset[1] = 0; offset[1] < m_GlobalWorkSize[1]; offset[1] += chunksDim[1]) + { + for(offset[2] = 0; offset[2] < m_GlobalWorkSize[2]; offset[2] += chunksDim[2]) + { + clErr |= clEnqueueNDRangeKernel( this->m_CommandQue, kernel, workSizeDim, + offset, chunksDim, m_LocalWorkSize, 0, nullptr, nullptr); + } + } + } + } + + CHECK_OCL_ERR(clErr); + + return ( clErr == CL_SUCCESS ); +} + +bool mitk::OclFilter::ExecuteKernelChunksInBatches(cl_kernel kernel, unsigned int workSizeDim, size_t* chunksDim, size_t batchSize, int waitTimems) +{ + size_t offset[3] = { 0, 0, 0 }; + cl_int clErr = 0; + + unsigned int currentChunk = 0; + cl_event* waitFor = new cl_event[batchSize]; + + if (workSizeDim == 2) + { + for (offset[0] = 0; offset[0] < m_GlobalWorkSize[0]; offset[0] += chunksDim[0]) + { + for (offset[1] = 0; offset[1] < m_GlobalWorkSize[1]; offset[1] += chunksDim[1]) + { + if (currentChunk % batchSize == 0 && currentChunk != 0) + { + clWaitForEvents(batchSize, &waitFor[0]); + std::this_thread::sleep_for(std::chrono::milliseconds(waitTimems)); + clErr |= clEnqueueNDRangeKernel(this->m_CommandQue, kernel, workSizeDim, + offset, chunksDim, m_LocalWorkSize, 0, nullptr, &waitFor[0]); + } + else + { + clErr |= clEnqueueNDRangeKernel(this->m_CommandQue, kernel, workSizeDim, + offset, chunksDim, m_LocalWorkSize, 0, nullptr, &waitFor[currentChunk % batchSize]); + } + currentChunk++; + } + } + } + else if (workSizeDim == 3) + { + for (offset[0] = 0; offset[0] < m_GlobalWorkSize[0]; offset[0] += chunksDim[0]) + { + for (offset[1] = 0; offset[1] < m_GlobalWorkSize[1]; offset[1] += chunksDim[1]) + { + for (offset[2] = 0; offset[2] < m_GlobalWorkSize[2]; offset[2] += chunksDim[2]) + { + if (currentChunk % batchSize == 0 && currentChunk != 0) + { + clWaitForEvents(batchSize, &waitFor[0]); + std::this_thread::sleep_for(std::chrono::milliseconds(waitTimems)); + clErr |= clEnqueueNDRangeKernel(this->m_CommandQue, kernel, workSizeDim, + offset, chunksDim, m_LocalWorkSize, 0, nullptr, &waitFor[0]); + } + else + { + clErr |= clEnqueueNDRangeKernel(this->m_CommandQue, kernel, workSizeDim, + offset, chunksDim, m_LocalWorkSize, 0, nullptr, &waitFor[currentChunk % batchSize]); + } + currentChunk++; + } + } + } + } + CHECK_OCL_ERR(clErr); + + return (clErr == CL_SUCCESS); +} + bool mitk::OclFilter::Initialize() { us::ServiceReference ref = GetModuleContext()->GetServiceReference(); OclResourceService* resources = GetModuleContext()->GetService(ref); m_CommandQue = resources->GetCommandQueue(); cl_int clErr = 0; m_Initialized = CHECK_OCL_ERR(clErr); if ( m_ClFiles.empty()) { MITK_ERROR<<"No OpenCL Source FILE specified"; return false; } if (m_ClProgram == nullptr) { try { this->m_ClProgram = resources->GetProgram( this->m_FilterID ); } catch(const mitk::Exception& e) { - MITK_INFO << "Program not stored in resource manager, compiling."; + MITK_INFO << "Program not stored in resource manager, compiling. " << e; this->CompileSource(); } } return m_Initialized; } void mitk::OclFilter::LoadSourceFiles(CStringList &sourceCode, ClSizeList &sourceCodeSize) { for( CStringList::iterator it = m_ClFiles.begin(); it != m_ClFiles.end(); ++it ) { MITK_DEBUG << "Load file :" << *it; us::ModuleResource mdr = GetModule()->GetResource(*it); if( !mdr.IsValid() ) MITK_WARN << "Could not load resource: " << mdr.GetName() << " is invalid!"; us::ModuleResourceStream rss(mdr); // read resource file to a string std::istreambuf_iterator eos; std::string source(std::istreambuf_iterator(rss), eos); // add preambel and build up string to compile std::string src(m_Preambel); src.append("\n"); src.append(source); // allocate new char buffer char* tmp = new char[src.size() + 1]; strcpy(tmp,src.c_str()); // add source to list sourceCode.push_back((const char*)tmp); sourceCodeSize.push_back(src.size()); } } void mitk::OclFilter::CompileSource() { // helper variable int clErr = 0; CStringList sourceCode; ClSizeList sourceCodeSize; if (m_ClFiles.empty()) { MITK_ERROR("ocl.filter") << "No shader source file was set"; return; } //get a valid opencl context us::ServiceReference ref = GetModuleContext()->GetServiceReference(); OclResourceService* resources = GetModuleContext()->GetService(ref); cl_context gpuContext = resources->GetContext(); // load the program source from file LoadSourceFiles(sourceCode, sourceCodeSize); if ( !sourceCode.empty() ) { // create program from all files in the file list m_ClProgram = clCreateProgramWithSource(gpuContext, sourceCode.size(), &sourceCode[0], &sourceCodeSize[0], &clErr); CHECK_OCL_ERR(clErr); // build the source code MITK_DEBUG << "Building Program Source"; std::string compilerOptions = ""; compilerOptions.append(m_ClCompilerFlags); MITK_DEBUG("ocl.filter") << "cl compiler flags: " << compilerOptions.c_str(); clErr = clBuildProgram(m_ClProgram, 0, nullptr, compilerOptions.c_str(), nullptr, nullptr); CHECK_OCL_ERR(clErr); // if OpenCL Source build failed if (clErr != CL_SUCCESS) { MITK_ERROR("ocl.filter") << "Failed to build source"; oclLogBuildInfo(m_ClProgram, resources->GetCurrentDevice() ); oclLogBinary(m_ClProgram, resources->GetCurrentDevice() ); m_Initialized = false; } // store the succesfully build program into the program storage provided by the resource service resources->InsertProgram(m_ClProgram, m_FilterID, true); // free the char buffers with the source code for( CStringList::iterator it = sourceCode.begin(); it != sourceCode.end(); ++it ) { delete[] *it; } } else { MITK_ERROR("ocl.filter") << "Could not load from source"; m_Initialized = false; } } void mitk::OclFilter::SetWorkingSize(unsigned int locx, unsigned int dimx, unsigned int locy, unsigned int dimy, unsigned int locz, unsigned int dimz) { // set the local work size this->m_LocalWorkSize[0] = locx; this->m_LocalWorkSize[1] = locy; this->m_LocalWorkSize[2] = locz; this->m_GlobalWorkSize[0] = dimx; this->m_GlobalWorkSize[1] = dimy; this->m_GlobalWorkSize[2] = dimz; // estimate the global work size this->m_GlobalWorkSize[0] = iDivUp( dimx, this->m_LocalWorkSize[0]) * this->m_LocalWorkSize[0]; if ( dimy > 1) this->m_GlobalWorkSize[1] = iDivUp( dimy, this->m_LocalWorkSize[1]) * this->m_LocalWorkSize[1]; if( dimz > 1 ) this->m_GlobalWorkSize[2] = iDivUp( dimz, this->m_LocalWorkSize[2]) * this->m_LocalWorkSize[2]; } void mitk::OclFilter::SetSourcePreambel(const char* preambel) { this->m_Preambel = preambel; } void mitk::OclFilter::AddSourceFile(const char* filename) { m_ClFiles.push_back(filename); } void mitk::OclFilter::SetCompilerFlags(const char* flags) { m_ClCompilerFlags = flags; } bool mitk::OclFilter::IsInitialized() { return m_Initialized; } + +long mitk::OclFilter::GetDeviceMemory() +{ + OclResourceService* resources = GetModuleContext()->GetService(GetModuleContext()->GetServiceReference()); + auto device = resources->GetCurrentDevice(); + return oclGetGlobalMemSize(device); +} \ No newline at end of file diff --git a/Modules/OpenCL/mitkOclFilter.h b/Modules/OpenCL/mitkOclFilter.h index e4b1bb67fb..89f557bd07 100644 --- a/Modules/OpenCL/mitkOclFilter.h +++ b/Modules/OpenCL/mitkOclFilter.h @@ -1,149 +1,162 @@ /*=================================================================== 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 __mitkOclFilter_h #define __mitkOclFilter_h #include "mitkOclUtils.h" #include "mitkCommon.h" #include #include #include namespace mitk { /** @class OclFilter @brief Superclass for all OpenCL based filter. This class takes care of loading and compiling the external GPU program code. */ class MITKOPENCL_EXPORT OclFilter { public: /** * @brief Add a source file from the resource files to the * OpenCL shader file list. Multiple files can be added to the list. * * @param name of the file in the resource system */ void AddSourceFile(const char* filename); /** * @brief Set specific compilerflags to compile the CL source. Default is set to nullptr; * example: "-cl-fast-relaxed-math -cl-mad-enable -cl-strict-aliasing" * * @param flags to the modulefolder that contains the gpuSource */ void SetCompilerFlags(const char* flags); /** * @brief Returns true if the initialization was successfull */ virtual bool IsInitialized(); + /** + * @brief Returns the amount of global memory of the used device in bytes + */ + virtual long GetDeviceMemory(); + /** @brief Destructor */ virtual ~OclFilter(); protected: typedef std::vector CStringList; typedef std::vector ClSizeList; /** @brief Constructor */ OclFilter(); /** @brief Constructor ( overloaded ) */ OclFilter(const char* filename); /** @brief String that contains the compiler flags */ const char* m_ClCompilerFlags; /** @brief The compiled OpenCL program */ cl_program m_ClProgram; /** @brief Command queue for the filter */ cl_command_queue m_CommandQue; /** @brief Unique ID of the filter, needs to be specified in the constructor of the derived class */ std::string m_FilterID; /*! @brief source preambel for e.g. #define commands to be inserted into the OpenCL source */ const char* m_Preambel; /** @brief List of sourcefiles that will be compiled for this filter.*/ CStringList m_ClFiles; /** @brief status of the filter */ bool m_Initialized; /** @brief The local work size fo the filter */ size_t m_LocalWorkSize[3]; /** @brief The global work size of the filter */ size_t m_GlobalWorkSize[3]; /** @brief Set the working size for the following OpenCL kernel call */ void SetWorkingSize(unsigned int locx, unsigned int dimx, unsigned int locy = 1, unsigned int dimy = 1, unsigned int locz = 1, unsigned int dimz = 1); /** @brief Execute the given kernel on the OpenCL Index-Space defined by the local and global work sizes */ bool ExecuteKernel( cl_kernel kernel, unsigned int workSizeDim ); + /** @brief Execute the given kernel on the OpenCL Index-Space defined by the local and global work sizes, but divide it into chunks of dimension chunksDim + */ + bool ExecuteKernelChunks( cl_kernel kernel, unsigned int workSizeDim, size_t* chunksDim ); + + /** @brief Execute the given kernel on the OpenCL Index-Space defined by the local and global work sizes, but divide it into chunks of dimension chunksDim and wait between + * batches of batchSize chunks a time of waitTimems milliseconds + */ + bool ExecuteKernelChunksInBatches(cl_kernel kernel, unsigned int workSizeDim, size_t* chunksDim, size_t batchSize, int waitTimems); /** * \brief Initialize all necessary parts of the filter * * The Initialize() method creates the command queue and the m_clProgram. * The program is either compiled from the given source or taken from the * OclResourceManager if the program was compiled already. */ bool Initialize(); /** * @brief Compile the program source * * @param preambel e.g. defines for the shader code */ void CompileSource(); /** * @brief Add some source code on the beginning of the loaded source * * In this way, some preprocessor flags for the CL compiler can at the beginning of the filter * @param preambel Source preambel for e.g. #define commands to be inserted into the OpenCL source */ void SetSourcePreambel(const char* preambel); /** * @brief Get the Module of the filter. Needs to be implemented by every subclass. * The filter will load the OpenCL sourcefiles from this module context. */ virtual us::Module* GetModule() = 0; /** * @brief Helper functions that load sourcefiles from the module context in the Initialize function. * @param SourceCodeList holds the sourcecode for every file as string, the SourceCodeSizeList holst the * size of every file in bytes. */ void LoadSourceFiles(CStringList &SourceCodeList, ClSizeList &SourceCodeSizeList); }; } #endif // __mitkOclFilter_h diff --git a/Modules/OpenCL/mitkOclImageToImageFilter.cpp b/Modules/OpenCL/mitkOclImageToImageFilter.cpp index f78d6f9def..10f88b06a4 100644 --- a/Modules/OpenCL/mitkOclImageToImageFilter.cpp +++ b/Modules/OpenCL/mitkOclImageToImageFilter.cpp @@ -1,193 +1,193 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkOclImageToImageFilter.h" #include "mitkOclImage.h" #include "mitkException.h" mitk::OclImageToImageFilter::OclImageToImageFilter() { m_Output = mitk::OclImage::New(); } mitk::OclImageToImageFilter::~OclImageToImageFilter() { } mitk::OclImage::Pointer mitk::OclImageToImageFilter::GetGPUOutput() { // initialize some variables m_Output->SetPixelType(m_Input->GetPixelType()); // create new image, for passing the essential information to the output m_Output->InitializeMITKImage(); const unsigned int dimension = m_Input->GetDimension(); unsigned int* dimensions = m_Input->GetDimensions(); m_Output->SetDimensions( dimensions ); m_Output->SetDimension( (unsigned short)dimension ); m_Output->GetMITKImage()->Initialize( this->GetOutputType(), dimension, dimensions); const mitk::SlicedGeometry3D::Pointer p_slg = m_Input->GetMITKImage()->GetSlicedGeometry(0); m_Output->GetMITKImage()->SetSpacing( p_slg->GetSpacing() ); m_Output->GetMITKImage()->SetGeometry( m_Input->GetMITKImage()->GetGeometry() ); return this->m_Output; } mitk::Image::Pointer mitk::OclImageToImageFilter::GetOutput() { if (m_Output->IsModified(GPU_DATA)) { void* pData = m_Output->TransferDataToCPU(m_CommandQue); const unsigned int dimension = m_Input->GetDimension(); unsigned int* dimensions = m_Input->GetDimensions(); const mitk::SlicedGeometry3D::Pointer p_slg = m_Input->GetMITKImage()->GetSlicedGeometry(); MITK_DEBUG << "Creating new MITK Image."; m_Output->GetMITKImage()->Initialize( this->GetOutputType(), dimension, dimensions); m_Output->GetMITKImage()->SetSpacing( p_slg->GetSpacing()); m_Output->GetMITKImage()->SetGeometry( m_Input->GetMITKImage()->GetGeometry() ); m_Output->GetMITKImage()->SetImportVolume( pData, 0, 0, mitk::Image::ReferenceMemory); } MITK_DEBUG << "Image Initialized."; return m_Output->GetMITKImage(); } mitk::PixelType mitk::OclImageToImageFilter::GetOutputType() { // get the current image format from the input image const cl_image_format* currentImFormat = this->m_Input->GetPixelType(); // return the value according to the current channel type switch( currentImFormat->image_channel_data_type ) { case CL_UNORM_INT8: return mitk::MakeScalarPixelType(); case CL_UNSIGNED_INT8: return mitk::MakeScalarPixelType(); case CL_UNORM_INT16: return mitk::MakeScalarPixelType(); default: return mitk::MakeScalarPixelType(); } } int mitk::OclImageToImageFilter::GetBytesPerElem() { return (this->m_CurrentType + 1); } bool mitk::OclImageToImageFilter::InitExec(cl_kernel ckKernel) { cl_int clErr = 0; if( m_Input.IsNull() ) mitkThrow() << "Input image is null."; // get image size once const unsigned int uiImageWidth = m_Input->GetDimension(0); const unsigned int uiImageHeight = m_Input->GetDimension(1); const unsigned int uiImageDepth = m_Input->GetDimension(2); // compute work sizes this->SetWorkingSize( 8, uiImageWidth, 8, uiImageHeight , 8, uiImageDepth ); cl_mem clBuffIn = m_Input->GetGPUImage(this->m_CommandQue); cl_mem clBuffOut = m_Output->GetGPUBuffer(); if (!clBuffIn) { if ( m_Input->TransferDataToGPU(m_CommandQue) != CL_SUCCESS ) { mitkThrow()<< "Could not create / initialize gpu image."; } clBuffIn = m_Input->GetGPUImage(m_CommandQue); } // output image not initialized if (!clBuffOut) { //TODO bpp, or SetImageWidth/Height/... MITK_DEBUG << "Create GPU Image call " << uiImageWidth<< "x"<CreateGPUImage(uiImageWidth, uiImageHeight, uiImageDepth, this->m_CurrentType + 1); } clErr = 0; clErr = clSetKernelArg(ckKernel, 0, sizeof(cl_mem), &clBuffIn); clErr |= clSetKernelArg(ckKernel, 1, sizeof(cl_mem), &clBuffOut); CHECK_OCL_ERR( clErr ); if( clErr != CL_SUCCESS ) mitkThrow() << "OpenCL Part initialization failed with " << GetOclErrorAsString(clErr); return( clErr == CL_SUCCESS ); } bool mitk::OclImageToImageFilter::InitExec(cl_kernel ckKernel, unsigned int* dimensions) { cl_int clErr = 0; if( m_Input.IsNull() ) mitkThrow() << "Input image is null."; // get image size once const unsigned int uiImageWidth = dimensions[0]; const unsigned int uiImageHeight = dimensions[1]; - const unsigned int uiImageDepth = dimensions[2]; + const unsigned int uiImageDepth = dimensions[2]+1; // compute work sizes this->SetWorkingSize( 8, uiImageWidth, 8, uiImageHeight , 8, uiImageDepth ); cl_mem clBuffIn = m_Input->GetGPUImage(this->m_CommandQue); cl_mem clBuffOut = m_Output->GetGPUBuffer(); if (!clBuffIn) { if ( m_Input->TransferDataToGPU(m_CommandQue) != CL_SUCCESS ) { mitkThrow()<< "Could not create / initialize gpu image."; } clBuffIn = m_Input->GetGPUImage(m_CommandQue); } // output image not initialized //TODO bpp, or SetImageWidth/Height/... MITK_INFO << "Create GPU Image call " << uiImageWidth<< "x"<CreateGPUImage(uiImageWidth, uiImageHeight, uiImageDepth, this->m_CurrentType + 1); clErr = 0; clErr = clSetKernelArg(ckKernel, 0, sizeof(cl_mem), &clBuffIn); clErr |= clSetKernelArg(ckKernel, 1, sizeof(cl_mem), &clBuffOut); CHECK_OCL_ERR( clErr ); if( clErr != CL_SUCCESS ) mitkThrow() << "OpenCL Part initialization failed with " << GetOclErrorAsString(clErr); return( clErr == CL_SUCCESS ); } \ No newline at end of file diff --git a/Modules/OpenCL/mitkOclUtils.cpp b/Modules/OpenCL/mitkOclUtils.cpp index d743b3d494..79970ce3af 100644 --- a/Modules/OpenCL/mitkOclUtils.cpp +++ b/Modules/OpenCL/mitkOclUtils.cpp @@ -1,572 +1,583 @@ /*=================================================================== 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 "mitkOclUtils.h" #include "mitkLogMacros.h" #include #include unsigned int iDivUp(unsigned int dividend, unsigned int divisor){ return (dividend % divisor == 0) ? (dividend / divisor) : (dividend / divisor + 1); } cl_int oclGetPlatformID(cl_platform_id* selectedPlatform) { cl_uint num_platforms = 0; cl_platform_id* clPlatformIDs; cl_int ciErrNum = 0; ciErrNum = clGetPlatformIDs( 0, nullptr, &num_platforms); if ( ciErrNum != CL_SUCCESS) { MITK_ERROR<<" Error " << ciErrNum << " in clGetPlatformIDs() \n"; throw std::bad_exception(); } else { clPlatformIDs = new cl_platform_id[num_platforms]; ciErrNum = clGetPlatformIDs( num_platforms, clPlatformIDs, nullptr); if(ciErrNum == CL_SUCCESS) { *selectedPlatform = clPlatformIDs[0]; } } return CL_SUCCESS; } void oclPrintMemObjectInfo(cl_mem memobj) { cl_int clErr = 0; MITK_INFO << "Examining cl_mem object: " << memobj << "\n------------------\n"; // CL_MEM_TYPE cl_mem_object_type objtype; clErr = clGetMemObjectInfo( memobj, CL_MEM_TYPE, sizeof(cl_mem_object_type),&objtype, nullptr); CHECK_OCL_ERR( clErr ); switch(objtype) { case CL_MEM_OBJECT_BUFFER: MITK_INFO << "CL_MEM_TYPE \t" << "BUFFER_OBJ" << "\n"; break; case CL_MEM_OBJECT_IMAGE2D: MITK_INFO << "CL_MEM_TYPE \t" << "2D IMAGE" << "\n"; break; case CL_MEM_OBJECT_IMAGE3D: MITK_INFO << "CL_MEM_TYPE \t" << "3D IMAGE" << "\n"; break; default: MITK_INFO << "CL_MEM_TYPE \t" << "[could not resolve]" << "\n"; break; } // CL_MEM_FLAGS cl_mem_flags flags; clErr = clGetMemObjectInfo( memobj, CL_MEM_FLAGS, sizeof(cl_mem_flags),&flags, nullptr); CHECK_OCL_ERR( clErr ); switch(flags) { case CL_MEM_READ_ONLY: MITK_INFO << "CL_MEM_FLAGS \t" << "CL_MEM_READ_ONLY" << "\n"; break; case CL_MEM_WRITE_ONLY: MITK_INFO << "CL_MEM_FLAGS \t" << "CL_MEM_WRITE_ONLY" << "\n"; break; case CL_MEM_READ_WRITE: MITK_INFO << "CL_MEM_FLAGS \t" << "CL_MEM_READ_WRITE" << "\n"; break; default: MITK_INFO << "CL_MEM_FLAGS \t" << "not resolved, " << flags << "\n"; break; } // get CL_MEM_SIZE size_t memsize; clErr = clGetMemObjectInfo( memobj, CL_MEM_SIZE, sizeof(memsize),&memsize, nullptr); CHECK_OCL_ERR( clErr ); MITK_INFO << "CL_MEM_SIZE \t" << memsize << "\n"; // get CL_MEM_HOST_PTR float *hostptr; clErr = clGetMemObjectInfo( memobj, CL_MEM_HOST_PTR, sizeof(void*), (void*) &hostptr, nullptr); CHECK_OCL_ERR( clErr ); MITK_INFO << "CL_MEM_HOST_PTR \t" << hostptr << "\n"; // get CL_CONTEXT cl_context gpuctxt; clErr = clGetMemObjectInfo( memobj, CL_MEM_CONTEXT, sizeof(cl_context), &gpuctxt, nullptr); CHECK_OCL_ERR( clErr ); MITK_INFO << "CL_CONTEXT \t\t" << gpuctxt << "\n"; // get CL_MEM_REFERENCE_COUNT cl_uint refs; clErr = clGetMemObjectInfo( memobj, CL_MEM_REFERENCE_COUNT, sizeof(cl_uint), &refs, nullptr); CHECK_OCL_ERR(clErr); MITK_INFO << "CL_REF_COUNT \t" << refs << "\n"; MITK_INFO << "================== \n" << std::endl; } void oclPrintDeviceInfo(cl_device_id device) { char device_string[1024]; clGetDeviceInfo(device, CL_DEVICE_NAME, sizeof(device_string), &device_string, nullptr); MITK_INFO("ocl.log")<< " Device : " << device_string; // CL_DEVICE_INFO cl_device_type type; clGetDeviceInfo(device, CL_DEVICE_TYPE, sizeof(type), &type, nullptr); if( type & CL_DEVICE_TYPE_CPU ) MITK_INFO("ocl.log")<<" CL_DEVICE_TYPE: CL_DEVICE_TYPE_CPU"; if( type & CL_DEVICE_TYPE_GPU ) MITK_INFO("ocl.log")<<" CL_DEVICE_TYPE: CL_DEVICE_TYPE_GPU"; if( type & CL_DEVICE_TYPE_ACCELERATOR ) MITK_INFO("ocl.log")<<" CL_DEVICE_TYPE: CL_DEVICE_TYPE_ACCELERATOR"; if( type & CL_DEVICE_TYPE_DEFAULT ) MITK_INFO("ocl.log")<<" CL_DEVICE_TYPE: CL_DEVICE_TYPE_DEFAULT"; // CL_DEVICE_MAX_COMPUTE_UNITS cl_uint compute_units; clGetDeviceInfo(device, CL_DEVICE_MAX_COMPUTE_UNITS, sizeof(compute_units), &compute_units, nullptr); MITK_INFO("ocl.log")<<" CL_DEVICE_MAX_COMPUTE_UNITS:" << compute_units; // CL_DEVICE_MAX_WORK_GROUP_SIZE size_t workitem_size[3]; clGetDeviceInfo(device, CL_DEVICE_MAX_WORK_ITEM_SIZES, sizeof(workitem_size), &workitem_size, nullptr); MITK_INFO("ocl.log")<<" CL_DEVICE_MAX_WORK_ITEM_SIZES:\t"<< workitem_size[0]<< workitem_size[1]<< workitem_size[2]; // CL_DEVICE_MAX_WORK_GROUP_SIZE size_t workgroup_size; clGetDeviceInfo(device, CL_DEVICE_MAX_WORK_GROUP_SIZE, sizeof(workgroup_size), &workgroup_size, nullptr); MITK_INFO("ocl.log")<<" CL_DEVICE_MAX_WORK_GROUP_SIZE:" << workgroup_size; // CL_DEVICE_MAX_CLOCK_FREQUENCY cl_uint clock_frequency; clGetDeviceInfo(device, CL_DEVICE_MAX_CLOCK_FREQUENCY, sizeof(clock_frequency), &clock_frequency, nullptr); MITK_INFO("ocl.log")<<" CL_DEVICE_MAX_CLOCK_FREQUENCY:"<< clock_frequency / 1000; // CL_DEVICE_IMAGE_SUPPORT cl_bool image_support; clGetDeviceInfo(device, CL_DEVICE_IMAGE_SUPPORT, sizeof(image_support), &image_support, nullptr); MITK_INFO("ocl.log")<<" CL_DEVICE_IMAGE_SUPPORT:\t" << image_support; // CL_DEVICE_GLOBAL_MEM_SIZE cl_ulong mem_size; clGetDeviceInfo(device, CL_DEVICE_GLOBAL_MEM_SIZE, sizeof(mem_size), &mem_size, nullptr); MITK_INFO("ocl.log")<<" CL_DEVICE_GLOBAL_MEM_SIZE:\t\t"<<(unsigned int)(mem_size / (1024 * 1024))<<"Mbytes"; // CL_DEVICE_LOCAL_MEM_SIZE clGetDeviceInfo(device, CL_DEVICE_LOCAL_MEM_SIZE, sizeof(mem_size), &mem_size, nullptr); MITK_INFO("ocl.log")<<" CL_DEVICE_LOCAL_MEM_SIZE:\t\t"<< (unsigned int)(mem_size / (1024)) <<"KByte\n"; + // CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE + clGetDeviceInfo(device, CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE, sizeof(mem_size), &mem_size, nullptr); + MITK_INFO("ocl.log") << " CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE:\t\t" << (unsigned int)(mem_size / (1024)) << "KByte"; + //check for image support properties clGetDeviceInfo(device, CL_DEVICE_IMAGE2D_MAX_WIDTH, sizeof(workgroup_size), &workgroup_size, nullptr); MITK_INFO("ocl.log")<<" CL_DEVICE_IMAGE2D_MAX_WIDTH:\t" << workgroup_size; clGetDeviceInfo(device, CL_DEVICE_IMAGE2D_MAX_HEIGHT, sizeof(workgroup_size), &workgroup_size, nullptr); MITK_INFO("ocl.log")<<" CL_DEVICE_IMAGE2D_MAX_HEIGHT:\t" << workgroup_size; clGetDeviceInfo(device, CL_DEVICE_IMAGE3D_MAX_WIDTH, sizeof(workgroup_size), &workgroup_size, nullptr); MITK_INFO("ocl.log")<<" CL_DEVICE_IMAGE3D_MAX_WIDTH:\t" << workgroup_size; clGetDeviceInfo(device, CL_DEVICE_IMAGE3D_MAX_HEIGHT, sizeof(workgroup_size), &workgroup_size, nullptr); MITK_INFO("ocl.log")<<" CL_DEVICE_IMAGE3D_MAX_HEIGHT:\t" << workgroup_size; clGetDeviceInfo(device, CL_DEVICE_IMAGE3D_MAX_DEPTH, sizeof(workgroup_size), &workgroup_size, nullptr); MITK_INFO("ocl.log")<<" CL_DEVICE_IMAGE3D_MAX_DEPTH:\t" << workgroup_size; // CL_DEVICE_QUEUE_PROPERTIES cl_command_queue_properties queue_properties; clGetDeviceInfo(device, CL_DEVICE_QUEUE_PROPERTIES, sizeof(queue_properties), &queue_properties, nullptr); if( queue_properties & CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE ) MITK_INFO("ocl.log")<<" CL_DEVICE_QUEUE_PROPERTIES:\t\t"<< "CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE"; if( queue_properties & CL_QUEUE_PROFILING_ENABLE ) MITK_INFO("ocl.log")<<" CL_DEVICE_QUEUE_PROPERTIES:\t\t"<< "CL_QUEUE_PROFILING_ENABLE"; } +cl_ulong oclGetGlobalMemSize(cl_device_id device) +{ + cl_ulong mem_size; + clGetDeviceInfo(device, CL_DEVICE_GLOBAL_MEM_SIZE, sizeof(mem_size), &mem_size, nullptr); + return mem_size; +} + std::string GetOclErrorAsString( int _clErr ) { std::string returnString("unkown error number: "+std::to_string(_clErr)+" \n"); switch(_clErr) { case CL_SUCCESS: returnString = "CL_SUCCESS\n"; break; case CL_DEVICE_NOT_FOUND: returnString = "CL_DEVICE_NOT_FOUND\n"; break; case CL_DEVICE_NOT_AVAILABLE: returnString = "CL_DEVICE_NOT_AVAILABLE\n"; break; /*case CL_DEVICE_COMPILER_NOT_AVAILABLE: returnString = "CL_DEVICE_COMPILER_NOT_AVAILABLE\n"; break; */ case CL_MEM_OBJECT_ALLOCATION_FAILURE : returnString = "CL_MEM_OBJECT_ALLOCATION_FAILURE\n"; break; case CL_OUT_OF_RESOURCES: returnString = "CL_OUT_OF_RESOURCES\n"; break; case CL_OUT_OF_HOST_MEMORY: returnString = "CL_OUT_OF_HOST_MEMORY\n"; break; case CL_PROFILING_INFO_NOT_AVAILABLE: returnString = "CL_PROFILING_INFO_NOT_AVAILABLE\n"; break; case CL_MEM_COPY_OVERLAP: returnString = "CL_MEM_COPY_OVERLAP\n"; break; case CL_IMAGE_FORMAT_MISMATCH: returnString = "CL_IMAGE_FORMAT_MISMATCH\n"; break; case CL_IMAGE_FORMAT_NOT_SUPPORTED: returnString = "CL_IMAGE_FORMAT_NOT_SUPPORTED\n"; break; case CL_BUILD_PROGRAM_FAILURE: returnString = "CL_BUILD_PROGRAM_FAILURE\n"; break; case CL_MAP_FAILURE: returnString = "CL_MAP_FAILURE\n"; break; case CL_INVALID_VALUE: returnString = "CL_INVALID_VALUE\n"; break; case CL_INVALID_DEVICE_TYPE: returnString = "CL_INVALID_DEVICE_TYPE\n"; break; case CL_INVALID_PLATFORM: returnString = "CL_INVALID_PLATFORM\n"; break; case CL_INVALID_DEVICE: returnString = "CL_INVALID_DEVICE\n"; break; case CL_INVALID_CONTEXT : returnString = "CL_INVALID_CONTEXT\n"; break; case CL_INVALID_QUEUE_PROPERTIES: returnString = "CL_INVALID_QUEUE_PROPERTIES\n"; break; case CL_INVALID_COMMAND_QUEUE: returnString = "CL_INVALID_COMMAND_QUEUE\n"; break; case CL_INVALID_HOST_PTR: returnString = "CL_INVALID_HOST_PTR\n"; break; case CL_INVALID_MEM_OBJECT: returnString = "CL_INVALID_MEM_OBJECT\n"; break; case CL_INVALID_IMAGE_FORMAT_DESCRIPTOR: returnString = "CL_INVALID_IMAGE_FORMAT_DESCRIPTOR\n"; break; case CL_INVALID_IMAGE_SIZE: returnString = "CL_INVALID_IMAGE_SIZE\n"; break; case CL_INVALID_SAMPLER : returnString = "CL_INVALID_SAMPLER\n"; break; case CL_INVALID_BINARY: returnString = "CL_INVALID_BINARY\n"; break; case CL_INVALID_BUILD_OPTIONS: returnString = "CL_INVALID_BUILD_OPTIONS\n"; break; case CL_INVALID_PROGRAM: returnString = "CL_INVALID_PROGRAM\n"; break; case CL_INVALID_PROGRAM_EXECUTABLE: returnString = "CL_INVALID_PROGRAM_EXECUTABLE\n"; break; case CL_INVALID_KERNEL_NAME: returnString = "CL_INVALID_KERNEL_NAME\n"; break; case CL_INVALID_KERNEL_DEFINITION: returnString = "CL_INVALID_KERNEL_DEFINITION\n"; break; case CL_INVALID_KERNEL : returnString = "CL_INVALID_KERNEL\n"; break; case CL_INVALID_ARG_INDEX : returnString = "CL_INVALID_ARG_INDEX\n"; break; case CL_INVALID_ARG_VALUE : returnString = "CL_INVALID_ARG_VALUE\n"; break; case CL_INVALID_ARG_SIZE : returnString = "CL_INVALID_ARG_SIZE\n"; break; case CL_INVALID_KERNEL_ARGS : returnString = "CL_INVALID_KERNEL_ARGS\n"; break; case CL_INVALID_WORK_DIMENSION: returnString = "CL_INVALID_WORK_DIMENSION\n"; break; case CL_INVALID_WORK_GROUP_SIZE: returnString = "CL_INVALID_WORK_GROUP_SIZE\n"; break; case CL_INVALID_WORK_ITEM_SIZE: returnString = "CL_INVALID_WORK_ITEM_SIZE\n"; break; case CL_INVALID_GLOBAL_OFFSET: returnString = "CL_INVALID_GLOBAL_OFFSET\n"; break; case CL_INVALID_EVENT_WAIT_LIST: returnString = "CL_INVALID_EVENT_WAIT_LIST\n"; break; case CL_INVALID_EVENT: returnString = "CL_INVALID_EVENT\n"; break; case CL_INVALID_OPERATION: returnString = "CL_INVALID_OPERATION\n"; break; case CL_INVALID_GL_OBJECT: returnString = "CL_INVALID_GL_OBJECT\n"; break; case CL_INVALID_BUFFER_SIZE : returnString = "CL_INVALID_BUFFER_SIZE\n"; break; case CL_INVALID_MIP_LEVEL : returnString = "CL_INVALID_MIP_LEVEL\n"; break; default: break; } return returnString; } void GetOclError(int _clErr) { if(_clErr == CL_SUCCESS) MITK_WARN << "Called GetOclErr() with no error value: [CL_SUCCESS]"; else MITK_ERROR << GetOclErrorAsString(_clErr); } bool oclCheckError(int _err, const char* filepath, int lineno) { if (_err) { MITK_ERROR<< "OpenCL Error at " << filepath <<":"<< lineno; GetOclError(_err); return 0; } return 1; } void GetSupportedImageFormats(cl_context _context, cl_mem_object_type _type) { const unsigned int entries = 500; cl_image_format* formats = new cl_image_format[entries]; cl_uint _written = 0; // OpenCL constant to catch error IDs cl_int ciErr1; // Get list of supported image formats for READ_ONLY access ciErr1 = clGetSupportedImageFormats( _context, CL_MEM_READ_ONLY, _type, entries, formats, &_written); CHECK_OCL_ERR(ciErr1); MITK_INFO << "Supported Image Formats, Image: CL_MEM_READ_ONLY \n"; for (unsigned int i=0; i<_written; i++) { MITK_INFO<< "ChannelType: " << GetImageTypeAsString(formats[i].image_channel_data_type) << "| ChannelOrder: "<< GetImageTypeAsString(formats[i].image_channel_order) <<"\n"; } _written = 0; // Get list of supported image formats for READ_WRITE access ciErr1 = clGetSupportedImageFormats( _context, CL_MEM_READ_WRITE, _type, entries, formats, &_written); CHECK_OCL_ERR(ciErr1); MITK_INFO << "Supported Image Formats, Image: CL_MEM_READ_WRITE (found: " << _written <<") \n"; for (unsigned int i=0; i<_written; i++) { MITK_INFO<< "ChannelType: " << GetImageTypeAsString(formats[i].image_channel_data_type) << "| ChannelOrder: "<< GetImageTypeAsString(formats[i].image_channel_order) <<"\n"; } _written = 0; // Get list of supported image formats for WRITE_ONLY access ciErr1 = clGetSupportedImageFormats( _context, CL_MEM_WRITE_ONLY, _type, entries, formats, &_written); CHECK_OCL_ERR(ciErr1); MITK_INFO << "Supported Image Formats, Image: CL_MEM_WRITE_ONLY (found: " << _written <<") \n"; for (unsigned int i=0; i<_written; i++) { MITK_INFO<< "ChannelType: " << GetImageTypeAsString(formats[i].image_channel_data_type) << "| ChannelOrder: "<< GetImageTypeAsString(formats[i].image_channel_order) <<"\n"; } } std::string GetImageTypeAsString( const unsigned int _in) { switch(_in) { case CL_R: return "CL_R "; break; case CL_A: return "CL_A "; break; case CL_RG: return "CL_RG "; break; case CL_RA: return "CL_RA "; break; case CL_RGB: return "CL_RGB "; break; case CL_RGBA: return "CL_RGBA "; break; case CL_BGRA: return "CL_BGRA "; break; case CL_ARGB: return "CL_ARGB "; break; case CL_INTENSITY: return "CL_INTENSITY "; break; case CL_LUMINANCE: return "CL_LUMINANCE "; break; case CL_SNORM_INT8: return "CL_SNORM_INT8 "; break; case CL_SNORM_INT16: return "CL_SNORM_INT16 "; break; case CL_UNORM_INT8: return "CL_UNORM_INT8 "; break; case CL_UNORM_INT16: return "CL_UNORM_INT16 "; break; case CL_UNORM_SHORT_565: return "CL_UNORM_SHORT_565 "; break; case CL_UNORM_SHORT_555: return "CL_UNORM_SHORT_555 "; break; case CL_UNORM_INT_101010: return "CL_UNORM_INT_101010 "; break; case CL_SIGNED_INT8: return "CL_SIGNED_INT8 "; break; case CL_SIGNED_INT16: return "CL_SIGNED_INT16 "; break; case CL_SIGNED_INT32: return "CL_SIGNED_INT32 "; break; case CL_UNSIGNED_INT8: return "CL_UNSIGNED_INT8 "; break; case CL_UNSIGNED_INT16: return "CL_UNSIGNED_INT16 "; break; case CL_UNSIGNED_INT32: return "CL_UNSIGNED_INT32 "; break; case CL_HALF_FLOAT: return "CL_HALF_FLOAT "; break; case CL_FLOAT: return "CL_FLOAT "; break; default: return "--"; break; } } void oclLogBinary(cl_program clProg, cl_device_id clDev) { // Grab the number of devices associated with the program cl_uint num_devices; clGetProgramInfo(clProg, CL_PROGRAM_NUM_DEVICES, sizeof(cl_uint), &num_devices, nullptr); // Grab the device ids cl_device_id* devices = (cl_device_id*) malloc(num_devices * sizeof(cl_device_id)); clGetProgramInfo(clProg, CL_PROGRAM_DEVICES, num_devices * sizeof(cl_device_id), devices, 0); // Grab the sizes of the binaries size_t* binary_sizes = (size_t*)malloc(num_devices * sizeof(size_t)); clGetProgramInfo(clProg, CL_PROGRAM_BINARY_SIZES, num_devices * sizeof(size_t), binary_sizes, nullptr); // Now get the binaries char** ptx_code = (char**)malloc(num_devices * sizeof(char*)); for( unsigned int i=0; i #include #define CHECK_OCL_ERR(_er) oclCheckError(_er, __FILE__, __LINE__); /** @brief Method to estimate an integer quotient C from given dividend and divisor higher or equal to the corresponding floating quotient If the divisor is a factor of the dividend, the dividend/divisor is an integer value and is returned. If not, the nearest higher integer is returned. So it holds for the return value C that C * divisor is equal or greater then the dividend. In OpenCL context useful for estimating the local/global working dimension of a NDRange so that all image data is covered by the parallelisation scheme. */ MITKOPENCL_EXPORT unsigned int iDivUp(unsigned int dividend, unsigned int divisor); /** @brief Returns the name of an OpenCL Error as a string Most of the OpenCL Methods ( cl ) return an integer error code. This method translates the error value given as parameter to the corresponding error name. For example the value -30 will be translated to CL_INVALID_VALUE */ MITKOPENCL_EXPORT std::string GetOclErrorAsString( int _clErr ); /** @brief Checks whether the given value corresponds to an OpenCL Error value and prints this message out as MITK_ERROR if yes */ MITKOPENCL_EXPORT void GetOclError(int _clErr); /** @brief Returns a platform ID of an OpenCL-capable GPU, or throws an exception */ MITKOPENCL_EXPORT cl_int oclGetPlatformID(cl_platform_id* selectedPlatform); /*! \brief Prints out the essential support information about current device */ MITKOPENCL_EXPORT void oclPrintDeviceInfo(cl_device_id); +/*! \brief Returns the Global memory size of the current device */ +MITKOPENCL_EXPORT cl_ulong oclGetGlobalMemSize(cl_device_id device); + /*! @brief Prints the available memory info about the given object to std::cout */ MITKOPENCL_EXPORT void oclPrintMemObjectInfo( cl_mem memobj); /*! \brief Checks the given code for errors and produces a std::cout output if the _err does not equal CL_SUCCESS. The output includes also the filename and the line number of the method call. */ MITKOPENCL_EXPORT bool oclCheckError(int _err, const char*, int); /*! \brief Logs the GPU Program binary code @param clProg: the OpenCL Program to log @param clDev: the OpenCL-capable device the program was tried to be compiled for */ MITKOPENCL_EXPORT void oclLogBinary(cl_program clProg, cl_device_id clDev); /*! \brief Shows the OpenCL-Program build info, called if clBuildProgram != CL_SUCCES @param clProg: the OpenCL Program to log @param clDev: the OpenCL-capable device the program was tried to be compiled for */ MITKOPENCL_EXPORT void oclLogBuildInfo(cl_program clProg, cl_device_id clDev); /** \brief Print out all supported image formats for given image type @param _type the image type ( CL_MEM_OBJECT_2D or CL_MEM_OBJECT_3D ) @param _context the OpenCL context to be examined */ MITKOPENCL_EXPORT void GetSupportedImageFormats(cl_context _context, cl_mem_object_type _type); /** @brief Translates the internal image type identifier to a human readable description string */ MITKOPENCL_EXPORT std::string GetImageTypeAsString( const unsigned int _in); #endif //mitkOclUtils_h diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/OCL/mitkPhotoacousticBModeFilter.cpp b/Modules/PhotoacousticsAlgorithms/Algorithms/OCL/mitkPhotoacousticBModeFilter.cpp deleted file mode 100644 index 891839b80a..0000000000 --- a/Modules/PhotoacousticsAlgorithms/Algorithms/OCL/mitkPhotoacousticBModeFilter.cpp +++ /dev/null @@ -1,103 +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 "mitkPhotoacousticBModeFilter.h" -#include "usServiceReference.h" - -mitk::PhotoacousticBModeFilter::PhotoacousticBModeFilter() - : m_PixelCalculation(NULL) -{ - this->AddSourceFile("BModeAbs.cl"); - this->AddSourceFile("BModeAbsLog.cl"); - - this->m_FilterID = "PixelCalculation"; -} - -mitk::PhotoacousticBModeFilter::~PhotoacousticBModeFilter() -{ - if (this->m_PixelCalculation) - { - clReleaseKernel(m_PixelCalculation); - } -} - -void mitk::PhotoacousticBModeFilter::Update() -{ - //Check if context & program available - if (!this->Initialize()) - { - us::ServiceReference ref = GetModuleContext()->GetServiceReference(); - OclResourceService* resources = GetModuleContext()->GetService(ref); - - // clean-up also the resources - resources->InvalidateStorage(); - mitkThrow() << "Filter is not initialized. Cannot update."; - } - else { - // Execute - this->Execute(); - } -} - -void mitk::PhotoacousticBModeFilter::Execute() -{ - try - { - this->InitExec(this->m_PixelCalculation); - } - catch (const mitk::Exception& e) - { - MITK_ERROR << "Catched exception while initializing filter: " << e.what(); - return; - } - - // execute the filter on a 3D NDRange - this->ExecuteKernel(m_PixelCalculation, 3); - - // signalize the GPU-side data changed - m_Output->Modified(GPU_DATA); -} - -us::Module *mitk::PhotoacousticBModeFilter::GetModule() -{ - return us::GetModuleContext()->GetModule(); -} - -bool mitk::PhotoacousticBModeFilter::Initialize() -{ - bool buildErr = true; - cl_int clErr = 0; - - if (OclFilter::Initialize()) - { - if(m_UseLogFilter) - this->m_PixelCalculation = clCreateKernel(this->m_ClProgram, "ckBmodeAbsLog", &clErr); - else - this->m_PixelCalculation = clCreateKernel(this->m_ClProgram, "ckBmodeAbs", &clErr); - buildErr |= CHECK_OCL_ERR(clErr); - } - return (OclFilter::IsInitialized() && buildErr); -} - -void mitk::PhotoacousticBModeFilter::SetInput(mitk::Image::Pointer image) -{ - if (image->GetDimension() != 3) - { - mitkThrowException(mitk::Exception) << "Input for " << this->GetNameOfClass() << - " is not 3D. The filter only supports 3D. Please change your input."; - } - OclImageToImageFilter::SetInput(image); -} diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/OCL/mitkPhotoacousticBModeFilter.h b/Modules/PhotoacousticsAlgorithms/Algorithms/OCL/mitkPhotoacousticBModeFilter.h deleted file mode 100644 index adc24614df..0000000000 --- a/Modules/PhotoacousticsAlgorithms/Algorithms/OCL/mitkPhotoacousticBModeFilter.h +++ /dev/null @@ -1,91 +0,0 @@ -/*=================================================================== - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. - -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. - -See LICENSE.txt or http://www.mitk.org for details. - -===================================================================*/ - -#ifndef _MITKPHOTOACOUSTICSOCLBEAMFORMER_H_ -#define _MITKPHOTOACOUSTICSOCLBEAMFORMER_H_ - -#include "mitkOclImageToImageFilter.h" -#include - -namespace mitk -{ - class OclImageToImageFilter; - - /** Documentation - * - * \brief The OclBinaryThresholdImageFilter computes a binary segmentation based on given - threshold values. - - * - * The filter requires two threshold values ( the upper and the lower threshold ) and two image values ( inside and outside ). The resulting voxel of the segmentation image is assigned the inside value 1 if the image value is between the given thresholds and the outside value otherwise. - */ - - - class PhotoacousticBModeFilter : public OclImageToImageFilter, public itk::Object - { - - public: - mitkClassMacroItkParent(PhotoacousticBModeFilter, itk::Object); - itkNewMacro(Self); - - /** - * @brief SetInput Set the input image. Only 3D images are supported for now. - * @param image a 3D image. - * @throw mitk::Exception if the dimesion is not 3. - */ - void SetInput(Image::Pointer image); - - /** Update the filter */ - void Update(); - - void SetParameters(bool useLogFilter) - { - m_UseLogFilter = useLogFilter; - } - - protected: - - /** Constructor */ - PhotoacousticBModeFilter(); - - /** Destructor */ - virtual ~PhotoacousticBModeFilter(); - - /** Initialize the filter */ - bool Initialize(); - - void Execute(); - - mitk::PixelType GetOutputType() - { - return mitk::MakeScalarPixelType(); - } - - int GetBytesPerElem() - { - return sizeof(float); - } - - virtual us::Module* GetModule(); - - - private: - /** The OpenCL kernel for the filter */ - cl_kernel m_PixelCalculation; - bool m_UseLogFilter; - }; -} -#endif \ No newline at end of file diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/OCL/mitkPhotoacousticOCLBeamformer.cpp b/Modules/PhotoacousticsAlgorithms/Algorithms/OCL/mitkPhotoacousticOCLBeamformer.cpp deleted file mode 100644 index 114810ddc9..0000000000 --- a/Modules/PhotoacousticsAlgorithms/Algorithms/OCL/mitkPhotoacousticOCLBeamformer.cpp +++ /dev/null @@ -1,177 +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 "mitkPhotoacousticOCLBeamformer.h" -#include "usServiceReference.h" - -mitk::PhotoacousticOCLBeamformer::PhotoacousticOCLBeamformer() -: m_PixelCalculation( NULL ) -{ - this->AddSourceFile("DASQuadratic.cl"); - this->AddSourceFile("DMASQuadratic.cl"); - this->AddSourceFile("DASspherical.cl"); - this->AddSourceFile("DMASspherical.cl"); - - this->m_FilterID = "PixelCalculation"; -} - -mitk::PhotoacousticOCLBeamformer::~PhotoacousticOCLBeamformer() -{ - if ( this->m_PixelCalculation ) - { - clReleaseKernel( m_PixelCalculation ); - } -} - -void mitk::PhotoacousticOCLBeamformer::Update() -{ - //Check if context & program available - if (!this->Initialize()) - { - us::ServiceReference ref = GetModuleContext()->GetServiceReference(); - OclResourceService* resources = GetModuleContext()->GetService(ref); - - // clean-up also the resources - resources->InvalidateStorage(); - mitkThrow() <<"Filter is not initialized. Cannot update."; - } - else{ - // Execute - this->Execute(); - } -} - -void mitk::PhotoacousticOCLBeamformer::Execute() -{ - cl_int clErr = 0; - - try - { - this->InitExec(this->m_PixelCalculation, m_OutputDim); - } - catch (const mitk::Exception& e) - { - MITK_ERROR << "Caught exception while initializing filter: " << e.what(); - return; - } - - if (m_Apodisation == nullptr) - { - MITK_INFO << "No apodisation function set; Beamforming will be done without any apodisation."; - m_Apodisation = new float[1]; - m_Apodisation[0] = 1; - m_ApodArraySize = 1; - } - - us::ServiceReference ref = GetModuleContext()->GetServiceReference(); - OclResourceService* resources = GetModuleContext()->GetService(ref); - cl_context gpuContext = resources->GetContext(); - - cl_mem cl_input = clCreateBuffer(gpuContext, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, sizeof(float) * m_ApodArraySize, m_Apodisation, &clErr); - CHECK_OCL_ERR(clErr); - - // set kernel arguments - clErr = clSetKernelArg( this->m_PixelCalculation, 2, sizeof(cl_mem), &cl_input); - clErr |= clSetKernelArg( this->m_PixelCalculation, 3, sizeof(cl_ushort), &(this->m_ApodArraySize) ); - clErr |= clSetKernelArg( this->m_PixelCalculation, 4, sizeof(cl_float), &(this->m_SpeedOfSound) ); - clErr |= clSetKernelArg( this->m_PixelCalculation, 5, sizeof(cl_float), &(this->m_TimeSpacing) ); - clErr |= clSetKernelArg( this->m_PixelCalculation, 6, sizeof(cl_float), &(this->m_Pitch) ); - clErr |= clSetKernelArg( this->m_PixelCalculation, 7, sizeof(cl_float), &(this->m_Angle) ); - clErr |= clSetKernelArg( this->m_PixelCalculation, 8, sizeof(cl_ushort), &(this->m_PAImage)); - clErr |= clSetKernelArg(this->m_PixelCalculation, 9, sizeof(cl_ushort), &(this->m_TransducerElements)); - - CHECK_OCL_ERR( clErr ); - - // execute the filter on a 3D NDRange - this->ExecuteKernel( m_PixelCalculation, 3); - - // signalize the GPU-side data changed - m_Output->Modified( GPU_DATA ); -} - -us::Module *mitk::PhotoacousticOCLBeamformer::GetModule() -{ - return us::GetModuleContext()->GetModule(); -} - -bool mitk::PhotoacousticOCLBeamformer::Initialize() -{ - bool buildErr = true; - cl_int clErr = 0; - - if ( OclFilter::Initialize() ) - { - switch (m_Algorithm) - { - case BeamformingAlgorithm::DASQuad: - { - this->m_PixelCalculation = clCreateKernel(this->m_ClProgram, "ckDASQuad", &clErr); - break; - } - case BeamformingAlgorithm::DMASQuad: - { - this->m_PixelCalculation = clCreateKernel(this->m_ClProgram, "ckDMASQuad", &clErr); - break; - } - case BeamformingAlgorithm::DASSphe: - { - this->m_PixelCalculation = clCreateKernel(this->m_ClProgram, "ckDASSphe", &clErr); - break; - } - case BeamformingAlgorithm::DMASSphe: - { - this->m_PixelCalculation = clCreateKernel(this->m_ClProgram, "ckDMASSphe", &clErr); - break; - } - } - buildErr |= CHECK_OCL_ERR( clErr ); - } - return (OclFilter::IsInitialized() && buildErr ); -} - -void mitk::PhotoacousticOCLBeamformer::SetInput(mitk::Image::Pointer image) -{ - if(image->GetDimension() != 3) - { - mitkThrowException(mitk::Exception) << "Input for " << this->GetNameOfClass() << - " is not 3D. The filter only supports 3D. Please change your input."; - } - OclImageToImageFilter::SetInput(image); -} - -mitk::Image::Pointer mitk::PhotoacousticOCLBeamformer::GetOutput() -{ - if (m_Output->IsModified(GPU_DATA)) - { - void* pData = m_Output->TransferDataToCPU(m_CommandQue); - - const unsigned int dimension = 3; - unsigned int* dimensions = m_OutputDim; - - const mitk::SlicedGeometry3D::Pointer p_slg = m_Input->GetMITKImage()->GetSlicedGeometry(); - - MITK_DEBUG << "Creating new MITK Image."; - - m_Output->GetMITKImage()->Initialize(this->GetOutputType(), dimension, dimensions); - m_Output->GetMITKImage()->SetSpacing(p_slg->GetSpacing()); - m_Output->GetMITKImage()->SetGeometry(m_Input->GetMITKImage()->GetGeometry()); - m_Output->GetMITKImage()->SetImportVolume(pData, 0, 0, mitk::Image::ReferenceMemory); - } - - MITK_DEBUG << "Image Initialized."; - - return m_Output->GetMITKImage(); -} diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/OCL/mitkPhotoacousticOCLBeamformer.h b/Modules/PhotoacousticsAlgorithms/Algorithms/OCL/mitkPhotoacousticOCLBeamformer.h deleted file mode 100644 index 9a7c90e0de..0000000000 --- a/Modules/PhotoacousticsAlgorithms/Algorithms/OCL/mitkPhotoacousticOCLBeamformer.h +++ /dev/null @@ -1,129 +0,0 @@ -/*=================================================================== - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. - -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. - -See LICENSE.txt or http://www.mitk.org for details. - -===================================================================*/ - -#ifndef _MITKPHOTOACOUSTICSOCLBEAMFORMER_H_ -#define _MITKPHOTOACOUSTICSOCLBEAMFORMER_H_ - -#include "mitkOclImageToImageFilter.h" -#include - -namespace mitk -{ -class OclImageToImageFilter; - -/** Documentation - * - * \brief The OclBinaryThresholdImageFilter computes a binary segmentation based on given - threshold values. - - * - * The filter requires two threshold values ( the upper and the lower threshold ) and two image values ( inside and outside ). The resulting voxel of the segmentation image is assigned the inside value 1 if the image value is between the given thresholds and the outside value otherwise. - */ - - -class PhotoacousticOCLBeamformer : public OclImageToImageFilter, public itk::Object -{ - -public: - mitkClassMacroItkParent(PhotoacousticOCLBeamformer, itk::Object); - itkNewMacro(Self); - - /** - * @brief SetInput Set the input image. Only 3D images are supported for now. - * @param image a 3D image. - * @throw mitk::Exception if the dimesion is not 3. - */ - void SetInput(Image::Pointer image); - - mitk::Image::Pointer GetOutput(); - - /** Update the filter */ - void Update(); - - void SetOutputDim( unsigned int outputDim[3]) - { - m_OutputDim[0] = outputDim[0]; - m_OutputDim[1] = outputDim[1]; - m_OutputDim[2] = outputDim[2]; - } - - void SetApodisation(float* apodisation, unsigned short apodArraySize) - { - m_ApodArraySize = apodArraySize; - m_Apodisation = apodisation; - } - - enum BeamformingAlgorithm { DASQuad, DMASQuad, DASSphe, DMASSphe }; - - void SetAlgorithm(BeamformingAlgorithm algorithm, bool PA) - { - m_Algorithm = algorithm; - m_PAImage = PA; - } - - void SetBeamformingParameters(float SpeedOfSound, float timeSpacing, float Pitch, float Angle, bool PAImage, unsigned short transducerElements) - { - m_SpeedOfSound = SpeedOfSound; - m_TimeSpacing = timeSpacing; - m_Pitch = Pitch; - m_Angle = Angle; - m_PAImage = PAImage; - m_TransducerElements = transducerElements; - } - -protected: - - /** Constructor */ - PhotoacousticOCLBeamformer(); - - /** Destructor */ - virtual ~PhotoacousticOCLBeamformer(); - - /** Initialize the filter */ - bool Initialize(); - - void Execute(); - - mitk::PixelType GetOutputType() - { - return mitk::MakeScalarPixelType(); - } - - int GetBytesPerElem() - { - return sizeof(float); - } - - virtual us::Module* GetModule(); - - -private: - /** The OpenCL kernel for the filter */ - cl_kernel m_PixelCalculation; - - unsigned int m_OutputDim[3]; - float* m_Apodisation; - unsigned short m_ApodArraySize; - BeamformingAlgorithm m_Algorithm; - unsigned short m_PAImage; - float m_SpeedOfSound; - float m_TimeSpacing; - float m_Pitch; - float m_Angle; - unsigned short m_TransducerElements; -}; -} -#endif \ No newline at end of file diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/mitkPhotoacousticBeamformingFilter.cpp b/Modules/PhotoacousticsAlgorithms/Algorithms/mitkPhotoacousticBeamformingFilter.cpp deleted file mode 100644 index 47587fb719..0000000000 --- a/Modules/PhotoacousticsAlgorithms/Algorithms/mitkPhotoacousticBeamformingFilter.cpp +++ /dev/null @@ -1,607 +0,0 @@ -/*=================================================================== -mitkPhotoacousticBeamformingFilter -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 "mitkPhotoacousticBeamformingFilter.h" -#include "mitkProperties.h" -#include "mitkImageReadAccessor.h" -#include -#include -#include -#include -#include -#include -#include "mitkImageCast.h" -#include - - -mitk::BeamformingFilter::BeamformingFilter() : m_OutputData(nullptr), m_InputData(nullptr) -{ - this->SetNumberOfIndexedInputs(1); - this->SetNumberOfRequiredInputs(1); - - m_ProgressHandle = [](int, std::string) {}; -} - -void mitk::BeamformingFilter::SetProgressHandle(std::function progressHandle) -{ - m_ProgressHandle = progressHandle; -} - -mitk::BeamformingFilter::~BeamformingFilter() -{ -} - -void mitk::BeamformingFilter::GenerateInputRequestedRegion() -{ - Superclass::GenerateInputRequestedRegion(); - - mitk::Image* output = this->GetOutput(); - mitk::Image* input = const_cast (this->GetInput()); - if (!output->IsInitialized()) - { - return; - } - - input->SetRequestedRegionToLargestPossibleRegion(); - - //GenerateTimeInInputRegion(output, input); -} - -void mitk::BeamformingFilter::GenerateOutputInformation() -{ - mitk::Image::ConstPointer input = this->GetInput(); - mitk::Image::Pointer output = this->GetOutput(); - - if ((output->IsInitialized()) && (this->GetMTime() <= m_TimeOfHeaderInitialization.GetMTime())) - return; - - itkDebugMacro(<< "GenerateOutputInformation()"); - - unsigned int dim[] = { m_Conf.ReconstructionLines, m_Conf.SamplesPerLine, input->GetDimension(2) }; - output->Initialize(mitk::MakeScalarPixelType(), 3, dim); - - mitk::Vector3D spacing; - spacing[0] = m_Conf.Pitch * m_Conf.TransducerElements * 1000 / m_Conf.ReconstructionLines; - spacing[1] = m_Conf.RecordTime / 2 * m_Conf.SpeedOfSound * 1000 / m_Conf.SamplesPerLine; - spacing[2] = 1; - - output->GetGeometry()->SetSpacing(spacing); - output->GetGeometry()->Modified(); - output->SetPropertyList(input->GetPropertyList()->Clone()); - - m_TimeOfHeaderInitialization.Modified(); -} - -void mitk::BeamformingFilter::GenerateData() -{ - GenerateOutputInformation(); - mitk::Image::Pointer input = this->GetInput(); - mitk::Image::Pointer output = this->GetOutput(); - - if (!output->IsInitialized()) - return; - - float inputDim[2] = { (float)input->GetDimension(0), (float)input->GetDimension(1) }; - float outputDim[2] = { (float)output->GetDimension(0), (float)output->GetDimension(1) }; - - unsigned short chunkSize = 2; // TODO: make this slightly less arbitrary - - unsigned int oclOutputDim[3] = { output->GetDimension(0), output->GetDimension(1), output->GetDimension(2) }; - - unsigned int oclOutputDimChunk[3] = { output->GetDimension(0), output->GetDimension(1), chunkSize}; - unsigned int oclInputDimChunk[3] = { input->GetDimension(0), input->GetDimension(1), chunkSize}; - - unsigned int oclOutputDimLastChunk[3] = { output->GetDimension(0), output->GetDimension(1), input->GetDimension(2) % chunkSize }; - unsigned int oclInputDimLastChunk[3] = { input->GetDimension(0), input->GetDimension(1), input->GetDimension(2) % chunkSize }; - - const int apodArraySize = m_Conf.TransducerElements * 4; // set the resolution of the apodization array - float* ApodWindow; - - // calculate the appropiate apodization window - switch (m_Conf.Apod) - { - case beamformingSettings::Apodization::Hann: - ApodWindow = VonHannFunction(apodArraySize); - break; - case beamformingSettings::Apodization::Hamm: - ApodWindow = HammFunction(apodArraySize); - break; - case beamformingSettings::Apodization::Box: - ApodWindow = BoxFunction(apodArraySize); - break; - default: - ApodWindow = BoxFunction(apodArraySize); - break; - } - - int progInterval = output->GetDimension(2) / 20 > 1 ? output->GetDimension(2) / 20 : 1; - // the interval at which we update the gui progress bar - - auto begin = std::chrono::high_resolution_clock::now(); // debbuging the performance... - if (!m_Conf.UseGPU) - { - for (unsigned int i = 0; i < output->GetDimension(2); ++i) // seperate Slices should get Beamforming seperately applied - { - mitk::ImageReadAccessor inputReadAccessor(input, input->GetSliceData(i)); - - m_OutputData = new float[m_Conf.ReconstructionLines*m_Conf.SamplesPerLine]; - m_InputDataPuffer = new float[input->GetDimension(0)*input->GetDimension(1)]; - - // first, we convert any data to float, which we use by default - if (input->GetPixelType().GetTypeAsString() == "scalar (float)" || input->GetPixelType().GetTypeAsString() == " (float)") - { - m_InputData = (float*)inputReadAccessor.GetData(); - } - else - { - MITK_INFO << "Pixel type is not float, abort"; - return; - } - - // fill the image with zeros - for (int l = 0; l < outputDim[0]; ++l) - { - for (int s = 0; s < outputDim[1]; ++s) - { - m_OutputData[l*(short)outputDim[1] + s] = 0; - } - } - - std::thread *threads = new std::thread[(short)outputDim[0]]; - - // every line will be beamformed in a seperate thread - if (m_Conf.Algorithm == beamformingSettings::BeamformingAlgorithm::DAS) - { - if (m_Conf.DelayCalculationMethod == beamformingSettings::DelayCalc::QuadApprox) - { - for (short line = 0; line < outputDim[0]; ++line) - { - threads[line] = std::thread(&BeamformingFilter::DASQuadraticLine, this, m_InputData, m_OutputData, inputDim, outputDim, line, ApodWindow, apodArraySize); - } - } - else if (m_Conf.DelayCalculationMethod == beamformingSettings::DelayCalc::Spherical) - { - for (short line = 0; line < outputDim[0]; ++line) - { - threads[line] = std::thread(&BeamformingFilter::DASSphericalLine, this, m_InputData, m_OutputData, inputDim, outputDim, line, ApodWindow, apodArraySize); - } - } - } - else if (m_Conf.Algorithm == beamformingSettings::BeamformingAlgorithm::DMAS) - { - if (m_Conf.DelayCalculationMethod == beamformingSettings::DelayCalc::QuadApprox) - { - for (short line = 0; line < outputDim[0]; ++line) - { - threads[line] = std::thread(&BeamformingFilter::DMASQuadraticLine, this, m_InputData, m_OutputData, inputDim, outputDim, line, ApodWindow, apodArraySize); - } - } - else if (m_Conf.DelayCalculationMethod == beamformingSettings::DelayCalc::Spherical) - { - for (short line = 0; line < outputDim[0]; ++line) - { - threads[line] = std::thread(&BeamformingFilter::DMASSphericalLine, this, m_InputData, m_OutputData, inputDim, outputDim, line, ApodWindow, apodArraySize); - } - } - } - // wait for all lines to finish - for (short line = 0; line < outputDim[0]; ++line) - { - threads[line].join(); - } - - output->SetSlice(m_OutputData, i); - - if (i % progInterval == 0) - m_ProgressHandle((int)((i + 1) / (float)output->GetDimension(2) * 100), "performing reconstruction"); - - delete[] m_OutputData; - delete[] m_InputDataPuffer; - m_OutputData = nullptr; - m_InputData = nullptr; - } - } - else - { - mitk::PhotoacousticOCLBeamformer::Pointer m_oclFilter = mitk::PhotoacousticOCLBeamformer::New(); - - try - { - if (m_Conf.Algorithm == beamformingSettings::BeamformingAlgorithm::DAS) - { - if (m_Conf.DelayCalculationMethod == beamformingSettings::DelayCalc::QuadApprox) - m_oclFilter->SetAlgorithm(PhotoacousticOCLBeamformer::BeamformingAlgorithm::DASQuad, true); - else if (m_Conf.DelayCalculationMethod == beamformingSettings::DelayCalc::Spherical) - m_oclFilter->SetAlgorithm(PhotoacousticOCLBeamformer::BeamformingAlgorithm::DASSphe, true); - } - else if (m_Conf.Algorithm == beamformingSettings::BeamformingAlgorithm::DMAS) - { - if (m_Conf.DelayCalculationMethod == beamformingSettings::DelayCalc::QuadApprox) - m_oclFilter->SetAlgorithm(PhotoacousticOCLBeamformer::BeamformingAlgorithm::DMASQuad, true); - else if (m_Conf.DelayCalculationMethod == beamformingSettings::DelayCalc::Spherical) - m_oclFilter->SetAlgorithm(PhotoacousticOCLBeamformer::BeamformingAlgorithm::DMASSphe, true); - } - m_oclFilter->SetApodisation(ApodWindow, apodArraySize); - m_oclFilter->SetOutputDim(oclOutputDimChunk); - m_oclFilter->SetBeamformingParameters(m_Conf.SpeedOfSound, m_Conf.TimeSpacing, m_Conf.Pitch, m_Conf.Angle, m_Conf.Photoacoustic, m_Conf.TransducerElements); - - if (chunkSize < oclOutputDim[2]) - { - bool skip = false; - for (unsigned int i = 0; !skip && i < ceil((float)oclOutputDim[2] / (float)chunkSize); ++i) - { - m_ProgressHandle(100 * ((float)(i * chunkSize) / (float)oclOutputDim[2]), "performing reconstruction"); - mitk::Image::Pointer chunk = mitk::Image::New(); - if ((int)((oclOutputDim[2]) - (i * chunkSize)) == (int)(1 + chunkSize)) - { - // A 3d image of 3rd dimension == 1 can not be processed by openCL, make sure that this case never arises - oclInputDimLastChunk[2] = input->GetDimension(2) % chunkSize + chunkSize; - oclOutputDimLastChunk[2] = input->GetDimension(2) % chunkSize + chunkSize; - - chunk->Initialize(input->GetPixelType(), 3, oclInputDimLastChunk); - m_oclFilter->SetOutputDim(oclOutputDimLastChunk); - skip = true; //skip the last chunk - } - else if ((oclOutputDim[2]) - (i * chunkSize) >= chunkSize) - chunk->Initialize(input->GetPixelType(), 3, oclInputDimChunk); - else - { - chunk->Initialize(input->GetPixelType(), 3, oclInputDimLastChunk); - m_oclFilter->SetOutputDim(oclOutputDimLastChunk); - } - - chunk->SetSpacing(input->GetGeometry()->GetSpacing()); - - mitk::ImageReadAccessor ChunkMove(input); - chunk->SetImportVolume((void*)&(((float*)const_cast(ChunkMove.GetData()))[i * chunkSize * input->GetDimension(0) * input->GetDimension(1)]), 0, 0, mitk::Image::ReferenceMemory); - - m_oclFilter->SetInput(chunk); - m_oclFilter->Update(); - auto out = m_oclFilter->GetOutput(); - - for (unsigned int s = i * chunkSize; s < oclOutputDim[2]; ++s) // TODO: make the bounds here smaller... - { - mitk::ImageReadAccessor copy(out, out->GetSliceData(s - i * chunkSize)); - output->SetImportSlice(const_cast(copy.GetData()), s, 0, 0, mitk::Image::ReferenceMemory); - } - } - } - else - { - m_ProgressHandle(50, "performing reconstruction"); - - m_oclFilter->SetOutputDim(oclOutputDim); - m_oclFilter->SetInput(input); - m_oclFilter->Update(); - - auto out = m_oclFilter->GetOutput(); - mitk::ImageReadAccessor copy(out); - output->SetImportVolume(const_cast(copy.GetData()), 0, 0, mitk::Image::ReferenceMemory); - } - } - catch (mitk::Exception &e) - { - std::string errorMessage = "Caught unexpected exception "; - errorMessage.append(e.what()); - MITK_ERROR << errorMessage; - } - } - - m_TimeOfHeaderInitialization.Modified(); - - auto end = std::chrono::high_resolution_clock::now(); - MITK_INFO << "Beamforming of " << output->GetDimension(2) << " Images completed in " << ((float)std::chrono::duration_cast(end - begin).count()) / 1000000 << "ms" << std::endl; -} - -void mitk::BeamformingFilter::Configure(beamformingSettings settings) -{ - m_Conf = settings; -} - -float* mitk::BeamformingFilter::VonHannFunction(int samples) -{ - float* ApodWindow = new float[samples]; - - for (int n = 0; n < samples; ++n) - { - ApodWindow[n] = (1 - cos(2 * M_PI * n / (samples - 1))) / 2; - } - - return ApodWindow; -} - -float* mitk::BeamformingFilter::HammFunction(int samples) -{ - float* ApodWindow = new float[samples]; - - for (int n = 0; n < samples; ++n) - { - ApodWindow[n] = 0.54 - 0.46*cos(2 * M_PI*n / (samples - 1)); - } - - return ApodWindow; -} - -float* mitk::BeamformingFilter::BoxFunction(int samples) -{ - float* ApodWindow = new float[samples]; - - for (int n = 0; n < samples; ++n) - { - ApodWindow[n] = 1; - } - - return ApodWindow; -} - -void mitk::BeamformingFilter::DASQuadraticLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize) -{ - float& inputS = inputDim[1]; - float& inputL = inputDim[0]; - - float& outputS = outputDim[1]; - float& outputL = outputDim[0]; - - short AddSample = 0; - short maxLine = 0; - short minLine = 0; - float delayMultiplicator = 0; - float l_i = 0; - float s_i = 0; - - float part = 0.07 * inputL; - float tan_phi = std::tan(m_Conf.Angle / 360 * 2 * M_PI); - float part_multiplicator = tan_phi * m_Conf.TimeSpacing * m_Conf.SpeedOfSound / m_Conf.Pitch * m_Conf.ReconstructionLines / m_Conf.TransducerElements; - float apod_mult = 1; - - short usedLines = (maxLine - minLine); - - //quadratic delay - l_i = line / outputL * inputL; - - for (short sample = 0; sample < outputS; ++sample) - { - s_i = (float)sample / outputS * inputS / 2; - - part = part_multiplicator*s_i; - - if (part < 1) - part = 1; - - maxLine = (short)std::min((l_i + part) + 1, inputL); - minLine = (short)std::max((l_i - part), 0.0f); - usedLines = (maxLine - minLine); - - apod_mult = apodArraySize / (maxLine - minLine); - - delayMultiplicator = pow((1 / (m_Conf.TimeSpacing*m_Conf.SpeedOfSound) * (m_Conf.Pitch*m_Conf.TransducerElements) / inputL), 2) / s_i / 2; - - for (short l_s = minLine; l_s < maxLine; ++l_s) - { - AddSample = delayMultiplicator * pow((l_s - l_i), 2) + s_i + (1 - m_Conf.Photoacoustic)*s_i; - if (AddSample < inputS && AddSample >= 0) - output[sample*(short)outputL + line] += input[l_s + AddSample*(short)inputL] * apodisation[(short)((l_s - minLine)*apod_mult)]; - else - --usedLines; - } - output[sample*(short)outputL + line] = output[sample*(short)outputL + line] / usedLines; - } -} - -void mitk::BeamformingFilter::DASSphericalLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize) -{ - float& inputS = inputDim[1]; - float& inputL = inputDim[0]; - - float& outputS = outputDim[1]; - float& outputL = outputDim[0]; - - short AddSample = 0; - short maxLine = 0; - short minLine = 0; - float l_i = 0; - float s_i = 0; - - float part = 0.07 * inputL; - float tan_phi = std::tan(m_Conf.Angle / 360 * 2 * M_PI); - float part_multiplicator = tan_phi * m_Conf.TimeSpacing * m_Conf.SpeedOfSound / m_Conf.Pitch * m_Conf.ReconstructionLines / m_Conf.TransducerElements; - float apod_mult = 1; - - short usedLines = (maxLine - minLine); - - //exact delay - - l_i = (float)line / outputL * inputL; - - for (short sample = 0; sample < outputS; ++sample) - { - s_i = (float)sample / outputS * inputS / 2; - - part = part_multiplicator*s_i; - - if (part < 1) - part = 1; - - maxLine = (short)std::min((l_i + part) + 1, inputL); - minLine = (short)std::max((l_i - part), 0.0f); - usedLines = (maxLine - minLine); - - apod_mult = apodArraySize / (maxLine - minLine); - - for (short l_s = minLine; l_s < maxLine; ++l_s) - { - AddSample = (int)sqrt( - pow(s_i, 2) - + - pow((1 / (m_Conf.TimeSpacing*m_Conf.SpeedOfSound) * ((l_s - l_i)*m_Conf.Pitch*m_Conf.TransducerElements) / inputL), 2) - ) + (1 - m_Conf.Photoacoustic)*s_i; - if (AddSample < inputS && AddSample >= 0) - output[sample*(short)outputL + line] += input[l_s + AddSample*(short)inputL] * apodisation[(short)((l_s - minLine)*apod_mult)]; - else - --usedLines; - } - output[sample*(short)outputL + line] = output[sample*(short)outputL + line] / usedLines; - } -} - -void mitk::BeamformingFilter::DMASQuadraticLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize) -{ - float& inputS = inputDim[1]; - float& inputL = inputDim[0]; - - float& outputS = outputDim[1]; - float& outputL = outputDim[0]; - - short maxLine = 0; - short minLine = 0; - float delayMultiplicator = 0; - float l_i = 0; - float s_i = 0; - - float part = 0.07 * inputL; - float tan_phi = std::tan(m_Conf.Angle / 360 * 2 * M_PI); - float part_multiplicator = tan_phi * m_Conf.TimeSpacing * m_Conf.SpeedOfSound / m_Conf.Pitch * m_Conf.ReconstructionLines / m_Conf.TransducerElements; - float apod_mult = 1; - - float mult = 0; - short usedLines = (maxLine - minLine); - - //quadratic delay - l_i = line / outputL * inputL; - - for (short sample = 0; sample < outputS; ++sample) - { - s_i = sample / outputS * inputS / 2; - - part = part_multiplicator*s_i; - - if (part < 1) - part = 1; - - maxLine = (short)std::min((l_i + part) + 1, inputL); - minLine = (short)std::max((l_i - part), 0.0f); - usedLines = (maxLine - minLine); - - apod_mult = apodArraySize / (maxLine - minLine); - - delayMultiplicator = pow((1 / (m_Conf.TimeSpacing*m_Conf.SpeedOfSound) * (m_Conf.Pitch*m_Conf.TransducerElements) / inputL), 2) / s_i / 2; - - //calculate the AddSamples beforehand to save some time - short* AddSample = new short[maxLine - minLine]; - for (short l_s = 0; l_s < maxLine - minLine; ++l_s) - { - AddSample[l_s] = (short)(delayMultiplicator * pow((minLine + l_s - l_i), 2) + s_i) + (1 - m_Conf.Photoacoustic)*s_i; - } - - for (short l_s1 = minLine; l_s1 < maxLine - 1; ++l_s1) - { - if (AddSample[l_s1 - minLine] < (short)inputS && AddSample[l_s1 - minLine] >= 0) - { - for (short l_s2 = l_s1 + 1; l_s2 < maxLine; ++l_s2) - { - if (AddSample[l_s2 - minLine] < inputS && AddSample[l_s2 - minLine] >= 0) - { - mult = input[l_s2 + AddSample[l_s2 - minLine] * (short)inputL] * apodisation[(short)((l_s2 - minLine)*apod_mult)] * input[l_s1 + AddSample[l_s1 - minLine] * (short)inputL] * apodisation[(short)((l_s1 - minLine)*apod_mult)]; - output[sample*(short)outputL + line] += sqrt(abs(mult)) * ((mult > 0) - (mult < 0)); - } - } - } - else - --usedLines; - } - - output[sample*(short)outputL + line] = 10 * output[sample*(short)outputL + line] / (pow(usedLines, 2) - (usedLines - 1)); - - delete[] AddSample; - } -} - -void mitk::BeamformingFilter::DMASSphericalLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize) -{ - float& inputS = inputDim[1]; - float& inputL = inputDim[0]; - - float& outputS = outputDim[1]; - float& outputL = outputDim[0]; - - short maxLine = 0; - short minLine = 0; - float l_i = 0; - float s_i = 0; - - float part = 0.07 * inputL; - float tan_phi = std::tan(m_Conf.Angle / 360 * 2 * M_PI); - float part_multiplicator = tan_phi * m_Conf.TimeSpacing * m_Conf.SpeedOfSound / m_Conf.Pitch * m_Conf.ReconstructionLines / m_Conf.TransducerElements; - float apod_mult = 1; - - float mult = 0; - - short usedLines = (maxLine - minLine); - - //exact delay - - l_i = line / outputL * inputL; - - for (short sample = 0; sample < outputS; ++sample) - { - s_i = sample / outputS * inputS / 2; - - part = part_multiplicator*s_i; - - if (part < 1) - part = 1; - - maxLine = (short)std::min((l_i + part) + 1, inputL); - minLine = (short)std::max((l_i - part), 0.0f); - usedLines = (maxLine - minLine); - - apod_mult = apodArraySize / (maxLine - minLine); - - //calculate the AddSamples beforehand to save some time - short* AddSample = new short[maxLine - minLine]; - for (short l_s = 0; l_s < maxLine - minLine; ++l_s) - { - AddSample[l_s] = (short)sqrt( - pow(s_i, 2) - + - pow((1 / (m_Conf.TimeSpacing*m_Conf.SpeedOfSound) * ((minLine + l_s - l_i)*m_Conf.Pitch*m_Conf.TransducerElements) / inputL), 2) - ) + (1 - m_Conf.Photoacoustic)*s_i; - } - - for (short l_s1 = minLine; l_s1 < maxLine - 1; ++l_s1) - { - if (AddSample[l_s1 - minLine] < inputS && AddSample[l_s1 - minLine] >= 0) - { - for (short l_s2 = l_s1 + 1; l_s2 < maxLine; ++l_s2) - { - if (AddSample[l_s2 - minLine] < inputS && AddSample[l_s2 - minLine] >= 0) - { - mult = input[l_s2 + AddSample[l_s2 - minLine] * (short)inputL] * apodisation[(int)((l_s2 - minLine)*apod_mult)] * input[l_s1 + AddSample[l_s1 - minLine] * (short)inputL] * apodisation[(int)((l_s1 - minLine)*apod_mult)]; - output[sample*(short)outputL + line] += sqrt(abs(mult)) * ((mult > 0) - (mult < 0)); - } - } - } - else - --usedLines; - } - - output[sample*(short)outputL + line] = 10 * output[sample*(short)outputL + line] / (pow(usedLines, 2) - (usedLines - 1)); - - delete[] AddSample; - } -} diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/mitkPhotoacousticBeamformingFilter.h b/Modules/PhotoacousticsAlgorithms/Algorithms/mitkPhotoacousticBeamformingFilter.h deleted file mode 100644 index e2654fc7fd..0000000000 --- a/Modules/PhotoacousticsAlgorithms/Algorithms/mitkPhotoacousticBeamformingFilter.h +++ /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. - -===================================================================*/ - - -#ifndef MITK_PHOTOACOUSTICS_BEAMFORMING_FILTER -#define MITK_PHOTOACOUSTICS_BEAMFORMING_FILTER - -#include "mitkImageToImageFilter.h" -#include - -namespace mitk { - - //##Documentation - //## @brief - //## @ingroup Process - class BeamformingFilter : public ImageToImageFilter - { - public: - mitkClassMacro(BeamformingFilter, ImageToImageFilter); - - itkFactorylessNewMacro(Self) - itkCloneMacro(Self) - - struct beamformingSettings - { - float Pitch = 0.0003; // [m] - float SpeedOfSound = 1540; // [m/s] - unsigned int SamplesPerLine = 2048; - unsigned int ReconstructionLines = 128; - float RecordTime = 0.00006; // [s] - float TimeSpacing = 0.0000000000001; // [s] - unsigned int TransducerElements = 128; - bool partial = false; - unsigned int CropBounds[2] = { 0,0 }; - - bool UseGPU = true; - - enum DelayCalc {QuadApprox, Spherical}; - DelayCalc DelayCalculationMethod = QuadApprox; - - enum Apodization {Hamm, Hann, Box}; - Apodization Apod = Hann; - - enum BeamformingAlgorithm {DMAS, DAS}; - BeamformingAlgorithm Algorithm = DAS; - - float Angle = 10; - bool Photoacoustic = true; - float BPHighPass = 50; - float BPLowPass = 50; - bool UseBP = false; - }; - - void Configure(beamformingSettings settings); - - void SetProgressHandle(std::function progressHandle); - - protected: - - BeamformingFilter(); - - ~BeamformingFilter(); - - virtual void GenerateInputRequestedRegion() override; - - virtual void GenerateOutputInformation() override; - - virtual void GenerateData() override; - - //##Description - //## @brief Time when Header was last initialized - itk::TimeStamp m_TimeOfHeaderInitialization; - - std::function m_ProgressHandle; - - float* VonHannFunction(int samples); - float* HammFunction(int samples); - float* BoxFunction(int samples); - - void DASQuadraticLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize); - void DASSphericalLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize); - - void DMASQuadraticLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize); - void DMASSphericalLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize); - - float* m_OutputData; - float* m_InputData; - float* m_InputDataPuffer; - - beamformingSettings m_Conf; - }; - -} // namespace mitk - -#endif //MITK_PHOTOACOUSTICS_BEAMFORMING_FILTER diff --git a/Modules/PhotoacousticsAlgorithms/CMakeLists.txt b/Modules/PhotoacousticsAlgorithms/CMakeLists.txt index a1bd2a69cf..7b8587334b 100644 --- a/Modules/PhotoacousticsAlgorithms/CMakeLists.txt +++ b/Modules/PhotoacousticsAlgorithms/CMakeLists.txt @@ -1,8 +1,16 @@ +set(dependencies_list MitkCore MitkAlgorithmsExt) + +IF(MITK_USE_OpenCL) + add_definitions(-DPHOTOACOUSTICS_USE_GPU) + set(dependencies_list ${dependencies_list} MitkOpenCL) + message("Using OpenCL in PhotoacousticAlgorithms") +ENDIF(MITK_USE_OpenCL) + MITK_CREATE_MODULE( SUBPROJECTS - DEPENDS MitkCore MitkAlgorithmsExt MitkOpenCL + DEPENDS ${dependencies_list} #AUTOLOAD_WITH MitkCore INCLUDE_DIRS PUBLIC Algorithms/ITKUltrasound Algorithms Algorithms/OCL INTERNAL_INCLUDE_DIRS ${INCLUDE_DIRS_INTERNAL} PACKAGE_DEPENDS ITK|ITKFFT+ITKImageCompose+ITKImageIntensity -) +) \ No newline at end of file diff --git a/Modules/PhotoacousticsAlgorithms/Documentation/doxygen/PAModule.dox b/Modules/PhotoacousticsAlgorithms/Documentation/doxygen/PAModule.dox new file mode 100644 index 0000000000..342a21f696 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Documentation/doxygen/PAModule.dox @@ -0,0 +1,45 @@ +/** +\page PAModulePage The Photoacoustic Algorithms Module + +\tableofcontents + +\section PAModulePageOverview Overview + +The Photoacoustic Algorithms Module provides a set of filters for beamforming and post-processing of photoacoustic and ultrasound data. +The main features are: +
    +
  • Management of all filters through a single class PhotoacousticImage +
  • Beamforming of ultrasound and photoacoustic image data. +
      +
    • Beamforming using the DAS and DMAS Algorithms. +
    • Optional real-time beamforming capabilities by the usage of openCL GPU computing +
    +
  • Post/Pre-Processing of any kind of images. +
      +
    • Crop Filter for removing artefacts in upper and lower edge of the image. +
    • Multiple B-Mode Filter implementations with resampling and logarithmic filter. +
    • Bandpass Filter +
    +
+ +To use the GPU capabilities of this module, openCL needs to be activated in CMAKE. The custom build option "camiPhotoacousticsWorkstation" activates all needed CMAKE options, as well as openCL. +To build the project using openCL, the openCL libraries provided by your graphic card vendor need to be installed. The GPU capabilies of this module have been only tested using nvidia hardware, but, as openCL has been also implemented by AMD, this should work on either one. (Those are included in the CUDA package for nvidia graphic card owners) + +The \link org_mitk_gui_qt_photoacoustics_imageprocessing Photoacoustic Imageprocessing plugin \endlink provides a GUI to access all of thePhotoacoustic Algorithms Module's filters. + +\section PAModuleClasses The Photoacoustic Algorithms Module's Classes + +
    +
  • mitk::PhotoacousticImage: The class where all filters are managed. +
  • mitk::BeamformingSettings: The class used by many filters for storing the configuration to be used when applying them. +
  • Five filters are currently implemented in the Photoacoustic Algorithms module: +
      +
    • mitk::PhotoacousticBModeFilter/mitk::PhotoacousticOCLBModeFilter: Two classes for the B-Mode filter on GPU and CPU. +
    • Resampling Filter: A resampling filter for post-processing. +
    • mitk::BeamformingFilter: A filter with a switch for GPU/CPU computation, to compute the beamformed image out of raw ultrasound/photoacoustic data. +
    • Crop Filter: A filter for cropping artifacts on the upper and lower edges of the image. +
    • Bandpass Filter: A Filter to filter image data in the fourier domain, using a tukey window to cut off low or high frequency parts of the image. +
    +
  • +
+*/ \ No newline at end of file diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/LICENSE b/Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/LICENSE similarity index 100% rename from Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/LICENSE rename to Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/LICENSE diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/README.rst b/Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/README.rst similarity index 100% rename from Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/README.rst rename to Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/README.rst diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkAnalyticSignalImageFilter.h b/Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkAnalyticSignalImageFilter.h similarity index 100% rename from Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkAnalyticSignalImageFilter.h rename to Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkAnalyticSignalImageFilter.h diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkAnalyticSignalImageFilter.hxx b/Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkAnalyticSignalImageFilter.hxx similarity index 100% rename from Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkAnalyticSignalImageFilter.hxx rename to Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkAnalyticSignalImageFilter.hxx diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkBModeImageFilter.h b/Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkBModeImageFilter.h similarity index 100% rename from Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkBModeImageFilter.h rename to Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkBModeImageFilter.h diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkBModeImageFilter.hxx b/Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkBModeImageFilter.hxx similarity index 100% rename from Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkBModeImageFilter.hxx rename to Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkBModeImageFilter.hxx diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkCurvilinearArraySpecialCoordinatesImage.h b/Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkCurvilinearArraySpecialCoordinatesImage.h similarity index 100% rename from Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkCurvilinearArraySpecialCoordinatesImage.h rename to Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkCurvilinearArraySpecialCoordinatesImage.h diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkCurvilinearArraySpecialCoordinatesImage.hxx b/Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkCurvilinearArraySpecialCoordinatesImage.hxx similarity index 100% rename from Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkCurvilinearArraySpecialCoordinatesImage.hxx rename to Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkCurvilinearArraySpecialCoordinatesImage.hxx diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkFFT1DComplexConjugateToRealImageFilter.h b/Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkFFT1DComplexConjugateToRealImageFilter.h similarity index 100% rename from Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkFFT1DComplexConjugateToRealImageFilter.h rename to Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkFFT1DComplexConjugateToRealImageFilter.h diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkFFT1DComplexConjugateToRealImageFilter.hxx b/Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkFFT1DComplexConjugateToRealImageFilter.hxx similarity index 100% rename from Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkFFT1DComplexConjugateToRealImageFilter.hxx rename to Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkFFT1DComplexConjugateToRealImageFilter.hxx diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkFFT1DComplexToComplexImageFilter.h b/Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkFFT1DComplexToComplexImageFilter.h similarity index 100% rename from Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkFFT1DComplexToComplexImageFilter.h rename to Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkFFT1DComplexToComplexImageFilter.h diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkFFT1DComplexToComplexImageFilter.hxx b/Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkFFT1DComplexToComplexImageFilter.hxx similarity index 100% rename from Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkFFT1DComplexToComplexImageFilter.hxx rename to Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkFFT1DComplexToComplexImageFilter.hxx diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkFFT1DRealToComplexConjugateImageFilter.h b/Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkFFT1DRealToComplexConjugateImageFilter.h similarity index 100% rename from Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkFFT1DRealToComplexConjugateImageFilter.h rename to Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkFFT1DRealToComplexConjugateImageFilter.h diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkFFT1DRealToComplexConjugateImageFilter.hxx b/Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkFFT1DRealToComplexConjugateImageFilter.hxx similarity index 100% rename from Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkFFT1DRealToComplexConjugateImageFilter.hxx rename to Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkFFT1DRealToComplexConjugateImageFilter.hxx diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkRegionFromReferenceImageFilter.h b/Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkRegionFromReferenceImageFilter.h similarity index 100% rename from Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkRegionFromReferenceImageFilter.h rename to Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkRegionFromReferenceImageFilter.h diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkRegionFromReferenceImageFilter.hxx b/Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkRegionFromReferenceImageFilter.hxx similarity index 100% rename from Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkRegionFromReferenceImageFilter.hxx rename to Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkRegionFromReferenceImageFilter.hxx diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkSpectra1DImageFilter.h b/Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkSpectra1DImageFilter.h similarity index 100% rename from Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkSpectra1DImageFilter.h rename to Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkSpectra1DImageFilter.h diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkSpectra1DImageFilter.hxx b/Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkSpectra1DImageFilter.hxx similarity index 100% rename from Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkSpectra1DImageFilter.hxx rename to Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkSpectra1DImageFilter.hxx diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkSpectra1DSupportWindowImageFilter.h b/Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkSpectra1DSupportWindowImageFilter.h similarity index 100% rename from Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkSpectra1DSupportWindowImageFilter.h rename to Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkSpectra1DSupportWindowImageFilter.h diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkSpectra1DSupportWindowImageFilter.hxx b/Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkSpectra1DSupportWindowImageFilter.hxx similarity index 100% rename from Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkSpectra1DSupportWindowImageFilter.hxx rename to Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkSpectra1DSupportWindowImageFilter.hxx diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkSpectra1DSupportWindowToMaskImageFilter.h b/Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkSpectra1DSupportWindowToMaskImageFilter.h similarity index 100% rename from Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkSpectra1DSupportWindowToMaskImageFilter.h rename to Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkSpectra1DSupportWindowToMaskImageFilter.h diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkSpectra1DSupportWindowToMaskImageFilter.hxx b/Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkSpectra1DSupportWindowToMaskImageFilter.hxx similarity index 100% rename from Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkSpectra1DSupportWindowToMaskImageFilter.hxx rename to Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkSpectra1DSupportWindowToMaskImageFilter.hxx diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkTimeGainCompensationImageFilter.h b/Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkTimeGainCompensationImageFilter.h similarity index 100% rename from Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkTimeGainCompensationImageFilter.h rename to Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkTimeGainCompensationImageFilter.h diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkTimeGainCompensationImageFilter.hxx b/Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkTimeGainCompensationImageFilter.hxx similarity index 100% rename from Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkTimeGainCompensationImageFilter.hxx rename to Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkTimeGainCompensationImageFilter.hxx diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkVnlFFT1DComplexConjugateToRealImageFilter.h b/Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkVnlFFT1DComplexConjugateToRealImageFilter.h similarity index 100% rename from Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkVnlFFT1DComplexConjugateToRealImageFilter.h rename to Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkVnlFFT1DComplexConjugateToRealImageFilter.h diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkVnlFFT1DComplexConjugateToRealImageFilter.hxx b/Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkVnlFFT1DComplexConjugateToRealImageFilter.hxx similarity index 100% rename from Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkVnlFFT1DComplexConjugateToRealImageFilter.hxx rename to Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkVnlFFT1DComplexConjugateToRealImageFilter.hxx diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkVnlFFT1DComplexToComplexImageFilter.h b/Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkVnlFFT1DComplexToComplexImageFilter.h similarity index 100% rename from Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkVnlFFT1DComplexToComplexImageFilter.h rename to Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkVnlFFT1DComplexToComplexImageFilter.h diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkVnlFFT1DComplexToComplexImageFilter.hxx b/Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkVnlFFT1DComplexToComplexImageFilter.hxx similarity index 100% rename from Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkVnlFFT1DComplexToComplexImageFilter.hxx rename to Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkVnlFFT1DComplexToComplexImageFilter.hxx diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkVnlFFT1DRealToComplexConjugateImageFilter.h b/Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkVnlFFT1DRealToComplexConjugateImageFilter.h similarity index 100% rename from Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkVnlFFT1DRealToComplexConjugateImageFilter.h rename to Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkVnlFFT1DRealToComplexConjugateImageFilter.h diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkVnlFFT1DRealToComplexConjugateImageFilter.hxx b/Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkVnlFFT1DRealToComplexConjugateImageFilter.hxx similarity index 100% rename from Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkVnlFFT1DRealToComplexConjugateImageFilter.hxx rename to Modules/PhotoacousticsAlgorithms/ITKFilter/ITKUltrasound/itkVnlFFT1DRealToComplexConjugateImageFilter.hxx diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/itkPhotoacousticBModeImageFilter.h b/Modules/PhotoacousticsAlgorithms/ITKFilter/itkPhotoacousticBModeImageFilter.h similarity index 100% rename from Modules/PhotoacousticsAlgorithms/Algorithms/itkPhotoacousticBModeImageFilter.h rename to Modules/PhotoacousticsAlgorithms/ITKFilter/itkPhotoacousticBModeImageFilter.h diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/itkPhotoacousticBModeImageFilter.hxx b/Modules/PhotoacousticsAlgorithms/ITKFilter/itkPhotoacousticBModeImageFilter.hxx similarity index 100% rename from Modules/PhotoacousticsAlgorithms/Algorithms/itkPhotoacousticBModeImageFilter.hxx rename to Modules/PhotoacousticsAlgorithms/ITKFilter/itkPhotoacousticBModeImageFilter.hxx diff --git a/Modules/PhotoacousticsAlgorithms/Resources/BModeAbs.cl b/Modules/PhotoacousticsAlgorithms/Resources/BModeAbs.cl index ce692acbb6..5dfd66d02d 100644 --- a/Modules/PhotoacousticsAlgorithms/Resources/BModeAbs.cl +++ b/Modules/PhotoacousticsAlgorithms/Resources/BModeAbs.cl @@ -1,41 +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. ===================================================================*/ __kernel void ckBmodeAbs( - __read_only image3d_t dSource, // input image - __global float* dDest // output buffer + __global float* dSource, // input image + __global float* dDest, // output buffer + unsigned int size ) { // get thread identifier unsigned int globalPosX = get_global_id(0); unsigned int globalPosY = get_global_id(1); unsigned int globalPosZ = get_global_id(2); - // get image width and weight - const unsigned int inputL = get_image_width( dSource ); - const unsigned int inputS = get_image_height( dSource ); - const unsigned int Slices = get_image_depth( dSource ); - - // create an image sampler - const sampler_t defaultSampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST ; + // get image width and height + unsigned short inputS = get_global_size(1); + unsigned short inputL = get_global_size(0); + unsigned short slices = get_global_size(2); // terminate non-valid threads - if ( globalPosX < inputL && globalPosY < inputS && globalPosZ < Slices ) + if ( globalPosX + inputL * globalPosY + inputL * inputS * globalPosZ < size ) { - - dDest[ globalPosZ * inputL * inputS + globalPosY * inputL + globalPosX ] = fabs(read_imagef( dSource, defaultSampler, (int4)(globalPosX, globalPosY, globalPosZ, 0 )).x); + dDest[ globalPosZ * inputL * inputS + globalPosY * inputL + globalPosX ] = fabs(dSource[ globalPosZ * inputL * inputS + globalPosY * inputL + globalPosX ]); } } \ No newline at end of file diff --git a/Modules/PhotoacousticsAlgorithms/Resources/BModeAbsLog.cl b/Modules/PhotoacousticsAlgorithms/Resources/BModeAbsLog.cl index 1daa1709e1..842e5a5b52 100644 --- a/Modules/PhotoacousticsAlgorithms/Resources/BModeAbsLog.cl +++ b/Modules/PhotoacousticsAlgorithms/Resources/BModeAbsLog.cl @@ -1,40 +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. ===================================================================*/ __kernel void ckBmodeAbsLog( - __read_only image3d_t dSource, // input image - __global float* dDest // output buffer + __global float* dSource, // input image + __global float* dDest, // output buffer + unsigned int size ) { // get thread identifier unsigned int globalPosX = get_global_id(0); unsigned int globalPosY = get_global_id(1); unsigned int globalPosZ = get_global_id(2); - // get image width and weight - const unsigned int inputL = get_image_width( dSource ); - const unsigned int inputS = get_image_height( dSource ); - const unsigned int Slices = get_image_depth( dSource ); - - // create an image sampler - const sampler_t defaultSampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST ; + // get image width and height + unsigned short inputS = get_global_size(1); + unsigned short inputL = get_global_size(0); + unsigned short slices = get_global_size(2); // terminate non-valid threads - if ( globalPosX < inputL && globalPosY < inputS && globalPosZ < Slices ) + if ( globalPosX + inputL * globalPosY + inputL * inputS * globalPosZ < size ) { - dDest[ globalPosZ * inputL * inputS + globalPosY * inputL + globalPosX ] = log(fabs((float)read_imagef( dSource, defaultSampler, (int4)(globalPosX, globalPosY, globalPosZ, 0 )).x)); + dDest[ globalPosZ * inputL * inputS + globalPosY * inputL + globalPosX ] = log(fabs(dSource[ globalPosZ * inputL * inputS + globalPosY * inputL + globalPosX ])); } } \ No newline at end of file diff --git a/Modules/PhotoacousticsAlgorithms/Resources/DAS.cl b/Modules/PhotoacousticsAlgorithms/Resources/DAS.cl new file mode 100644 index 0000000000..2540ec58db --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Resources/DAS.cl @@ -0,0 +1,64 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +__kernel void ckDAS( + __global float* dSource, // input image + __global float* dDest, // output buffer + __global unsigned short* usedLines, + __global unsigned short* delays, + __constant float* apodArray, + unsigned short apodArraySize, + unsigned int inputL, + unsigned int inputS, + unsigned int Slices, + unsigned int outputL, + unsigned int outputS // parameters +) +{ + // get thread identifier + unsigned int globalPosX = get_global_id(0); + unsigned int globalPosY = get_global_id(1); + unsigned int globalPosZ = get_global_id(2); + + // terminate non-valid threads + if ( globalPosX < outputL && globalPosY < outputS && globalPosZ < Slices ) + { + float l_i = (float)globalPosX / (float)outputL * (float)inputL; + + unsigned short curUsedLines = usedLines[globalPosY * 3 * outputL + 3 * globalPosX]; + unsigned short minLine = usedLines[globalPosY * 3 * outputL + 3 * globalPosX + 1]; + unsigned short maxLine = usedLines[globalPosY * 3 *outputL + 3 * globalPosX + 2]; + + float apod_mult = (float)apodArraySize / (float)curUsedLines; + + unsigned short Delay = 0; + + float output = 0; + float mult = 0; + + for (short l_s = minLine; l_s < maxLine; ++l_s) + { + Delay = delays[globalPosY * (outputL / 2) + (int)(fabs(l_s - l_i)/(float)inputL * (float)outputL)]; + if (Delay < inputS && Delay >= 0) { + output += apodArray[(int)((l_s - minLine)*apod_mult)] * dSource[(int)(globalPosZ * inputL * inputS + Delay * inputL + l_s)]; + } + else + --curUsedLines; + } + + dDest[ globalPosZ * outputL * outputS + globalPosY * outputL + globalPosX ] = output / (float)curUsedLines; + } +} \ No newline at end of file diff --git a/Modules/PhotoacousticsAlgorithms/Resources/DASQuadratic.cl b/Modules/PhotoacousticsAlgorithms/Resources/DASQuadratic.cl deleted file mode 100644 index 8afda8ff42..0000000000 --- a/Modules/PhotoacousticsAlgorithms/Resources/DASQuadratic.cl +++ /dev/null @@ -1,76 +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. - -===================================================================*/ - -__kernel void ckDASQuad( - __read_only image3d_t dSource, // input image - __global float* dDest, // output buffer - __global float* apodArray, - unsigned short apodArraySize, - float SpeedOfSound, - float TimeSpacing, - float Pitch, - float Angle, - unsigned short PAImage, - unsigned short TransducerElements // parameters -) -{ - // get thread identifier - unsigned int globalPosX = get_global_id(0); - unsigned int globalPosY = get_global_id(1); - unsigned int globalPosZ = get_global_id(2); - - unsigned short outputS = get_global_size(1); - unsigned short outputL = get_global_size(0); - - // get image width and weight - const unsigned int inputL = get_image_width( dSource ); - const unsigned int inputS = get_image_height( dSource ); - const unsigned int Slices = get_image_depth( dSource ); - - // create an image sampler - const sampler_t defaultSampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST ; - - // terminate non-valid threads - if ( globalPosX < outputL && globalPosY < outputS && globalPosZ < Slices ) - { - float l_i = (float)globalPosX / outputL * inputL; - float s_i = (float)globalPosY / outputS * inputS / 2; - - float part = (tan(Angle / 360 * 2 * M_PI) * TimeSpacing * SpeedOfSound / Pitch * outputL / TransducerElements) * s_i; - if (part < 1) - part = 1; - - short maxLine = min((l_i + part) + 1, (float)inputL); - short minLine = max((l_i - part), 0.0f); - short usedLines = (maxLine - minLine); - float apod_mult = apodArraySize / (maxLine - minLine); - - short AddSample = 0; - float output = 0; - float delayMultiplicator = pow(1 / (TimeSpacing*SpeedOfSound) * Pitch * TransducerElements / inputL, 2) / s_i / 2; - - for (short l_s = minLine; l_s < maxLine; ++l_s) - { - AddSample = delayMultiplicator * pow((l_s - l_i), 2) + s_i + (1-PAImage)*s_i; - if (AddSample < inputS && AddSample >= 0) - output += apodArray[(short)((l_s - minLine)*apod_mult)] * read_imagef( dSource, defaultSampler, (int4)(l_s, AddSample, globalPosZ, 0 )).x; - else - --usedLines; - } - - dDest[ globalPosZ * outputL * outputS + globalPosY * outputL + globalPosX ] = output / usedLines; - } -} \ No newline at end of file diff --git a/Modules/PhotoacousticsAlgorithms/Resources/DASspherical.cl b/Modules/PhotoacousticsAlgorithms/Resources/DASspherical.cl deleted file mode 100644 index f9a11f7504..0000000000 --- a/Modules/PhotoacousticsAlgorithms/Resources/DASspherical.cl +++ /dev/null @@ -1,79 +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. - -===================================================================*/ - -__kernel void ckDASSphe( - __read_only image3d_t dSource, // input image - __global float* dDest, // output buffer - __global float* apodArray, - unsigned short apodArraySize, - float SpeedOfSound, - float TimeSpacing, - float Pitch, - float Angle, - unsigned short PAImage, - unsigned short TransducerElements // parameters -) -{ - // get thread identifier - unsigned int globalPosX = get_global_id(0); - unsigned int globalPosY = get_global_id(1); - unsigned int globalPosZ = get_global_id(2); - - unsigned short outputS = get_global_size(1); - unsigned short outputL = get_global_size(0); - - // get image width and weight - const unsigned int inputL = get_image_width( dSource ); - const unsigned int inputS = get_image_height( dSource ); - const unsigned int Slices = get_image_depth( dSource ); - - // create an image sampler - const sampler_t defaultSampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST ; - - // terminate non-valid threads - if ( globalPosX < outputL && globalPosY < outputS && globalPosZ < Slices ) - { - float l_i = (float)globalPosX / outputL * inputL; - float s_i = (float)globalPosY / outputS * inputS / 2; - - float part = (tan(Angle / 360 * 2 * M_PI) * TimeSpacing * SpeedOfSound / Pitch * outputL / TransducerElements) * s_i; - if (part < 1) - part = 1; - - short maxLine = min((l_i + part) + 1, (float)inputL); - short minLine = max((l_i - part), 0.0f); - short usedLines = (maxLine - minLine); - float apod_mult = apodArraySize / (maxLine - minLine); - - short AddSample = 0; - float output = 0; - - for (short l_s = minLine; l_s < maxLine; ++l_s) - { - AddSample = sqrt( - pow(s_i, 2) - + - pow((1 / (TimeSpacing*SpeedOfSound) * ((l_s - l_i)*Pitch*TransducerElements) / inputL), 2) - ) + (1-PAImage)*s_i; - if (AddSample < inputS && AddSample >= 0) - output += apodArray[(short)((l_s - minLine)*apod_mult)] * read_imagef( dSource, defaultSampler, (int4)(l_s, AddSample, globalPosZ, 0 )).x; - else - --usedLines; - } - - dDest[ globalPosZ * outputL * outputS + globalPosY * outputL + globalPosX ] = output / usedLines; - } -} \ No newline at end of file diff --git a/Modules/PhotoacousticsAlgorithms/Resources/DMAS.cl b/Modules/PhotoacousticsAlgorithms/Resources/DMAS.cl new file mode 100644 index 0000000000..89cc58bf12 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Resources/DMAS.cl @@ -0,0 +1,85 @@ +/*=================================================================== + +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. + +===================================================================*/ + +__kernel void ckDMAS( + __global float* dSource, // input image + __global float* dDest, // output buffer + __global unsigned short* usedLines, + __global unsigned short* AddSamples, + __constant float* apodArray, + unsigned short apodArraySize, + unsigned int inputL, + unsigned int inputS, + unsigned int Slices, + unsigned int outputL, + unsigned int outputS // parameters +) +{ + // get thread identifier + unsigned int globalPosX = get_global_id(0); + unsigned int globalPosY = get_global_id(1); + unsigned int globalPosZ = get_global_id(2); + + // terminate non-valid threads + if ( globalPosX < outputL && globalPosY < outputS && globalPosZ < Slices ) + { + float l_i = (float)globalPosX / (float)outputL * (float)inputL; + + unsigned short curUsedLines = usedLines[globalPosY * 3 * outputL + 3 * globalPosX]; + unsigned short minLine = usedLines[globalPosY * 3 * outputL + 3 * globalPosX + 1]; + unsigned short maxLine = usedLines[globalPosY * 3 *outputL + 3 * globalPosX + 2]; + + float apod_mult = (float)apodArraySize / (float)curUsedLines; + + unsigned short Delay1 = 0; + unsigned short Delay2 = 0; + + float output = 0; + float mult = 0; + + float s_1 = 0; + float s_2 = 0; + float apod_1 = 0; + + for (short l_s1 = minLine; l_s1 < maxLine; ++l_s1) + { + Delay1 = AddSamples[globalPosY * (outputL / 2) + (int)(fabs(l_s1 - l_i)/(float)inputL * (float)outputL)]; + if (Delay1 < inputS && Delay1 >= 0) + { + s_1 = dSource[(int)(globalPosZ * inputL * inputS + Delay1 * inputL + l_s1)]; + apod_1 = apodArray[(int)((l_s1 - minLine)*apod_mult)]; + + for (short l_s2 = l_s1 + 1; l_s2 < maxLine; ++l_s2) + { + Delay2 = AddSamples[globalPosY * (outputL / 2) + (int)(fabs(l_s2 - l_i)/(float)inputL * (float)outputL)]; + if (Delay2 < inputS && Delay2 >= 0) + { + s_2 = dSource[(int)(globalPosZ * inputL * inputS + Delay2 * inputL + l_s2)]; + + mult = apodArray[(int)((l_s2 - minLine)*apod_mult)] * s_2 + * apod_1 * s_1; + + output += sqrt(fabs(mult)) * ((mult > 0) - (mult < 0)); + } + } + } + else + --curUsedLines; + } + + dDest[ globalPosZ * outputL * outputS + globalPosY * outputL + globalPosX ] = output / (float)(curUsedLines * curUsedLines - (curUsedLines - 1)); + } +} diff --git a/Modules/PhotoacousticsAlgorithms/Resources/DMASQuadratic.cl b/Modules/PhotoacousticsAlgorithms/Resources/DMASQuadratic.cl deleted file mode 100644 index 857b988746..0000000000 --- a/Modules/PhotoacousticsAlgorithms/Resources/DMASQuadratic.cl +++ /dev/null @@ -1,92 +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. - -===================================================================*/ - -__kernel void ckDMASQuad( - __read_only image3d_t dSource, // input image - __global float* dDest, // output buffer - __global float* apodArray, - unsigned short apodArraySize, - float SpeedOfSound, - float TimeSpacing, - float Pitch, - float Angle, - unsigned short PAImage, - unsigned short TransducerElements // parameters -) -{ - // get thread identifier - unsigned int globalPosX = get_global_id(0); - unsigned int globalPosY = get_global_id(1); - unsigned int globalPosZ = get_global_id(2); - - unsigned short outputS = get_global_size(1); - unsigned short outputL = get_global_size(0); - - // get image width and weight - const unsigned int inputL = get_image_width( dSource ); - const unsigned int inputS = get_image_height( dSource ); - const unsigned int Slices = get_image_depth( dSource ); - - // create an image sampler - const sampler_t defaultSampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST ; - - // terminate non-valid threads - if ( globalPosX < outputL && globalPosY < outputS && globalPosZ < Slices ) - { - float l_i = (float)globalPosX / outputL * inputL; - float s_i = (float)globalPosY / outputS * inputS / 2; - - float part = (tan(Angle / 360 * 2 * M_PI) * TimeSpacing * SpeedOfSound / Pitch * outputL / TransducerElements) * s_i; - if (part < 1) - part = 1; - - short maxLine = min((l_i + part) + 1, (float)inputL); - short minLine = max((l_i - part), 0.0f); - short usedLines = (maxLine - minLine); - float apod_mult = apodArraySize / (maxLine - minLine); - - float delayMultiplicator = pow((1 / (TimeSpacing*SpeedOfSound) * Pitch * TransducerElements / inputL), 2) / s_i / 2; - - float mult = 0; - float output = 0; - float AddSample1 = 0; - float AddSample2 = 0; - - for (short l_s1 = minLine; l_s1 < maxLine - 1; ++l_s1) - { - AddSample1 = delayMultiplicator * pow((l_s1 - l_i), 2) + s_i + (1-PAImage)*s_i; - if (AddSample1 < inputS && AddSample1 >= 0) - { - for (short l_s2 = l_s1 + 1; l_s2 < maxLine; ++l_s2) - { - AddSample2 = delayMultiplicator * pow((l_s2 - l_i), 2) + s_i + (1-PAImage)*s_i; - if (AddSample2 < inputS && AddSample2 >= 0) - { - mult = read_imagef( dSource, defaultSampler, (int4)(l_s2, AddSample2, globalPosZ, 0 )).x - * apodArray[(short)((l_s2 - minLine)*apod_mult)] - * read_imagef( dSource, defaultSampler, (int4)(l_s1, AddSample1, globalPosZ, 0 )).x - * apodArray[(short)((l_s1 - minLine)*apod_mult)]; - output += sqrt(mult * ((float)(mult>0)-(float)(mult<0))) * ((mult > 0) - (mult < 0)); - } - } - } - else - --usedLines; - } - - dDest[ globalPosZ * outputL * outputS + globalPosY * outputL + globalPosX ] = 10 * output / (pow((float)usedLines, 2.0f) - (usedLines - 1)); - } -} \ No newline at end of file diff --git a/Modules/PhotoacousticsAlgorithms/Resources/DMASspherical.cl b/Modules/PhotoacousticsAlgorithms/Resources/DMASspherical.cl deleted file mode 100644 index fc480b0820..0000000000 --- a/Modules/PhotoacousticsAlgorithms/Resources/DMASspherical.cl +++ /dev/null @@ -1,98 +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. - -===================================================================*/ - -__kernel void ckDMASSphe( - __read_only image3d_t dSource, // input image - __global float* dDest, // output buffer - __global float* apodArray, - unsigned short apodArraySize, - float SpeedOfSound, - float TimeSpacing, - float Pitch, - float Angle, - unsigned short PAImage, - unsigned short TransducerElements // parameters -) -{ - // get thread identifier - unsigned int globalPosX = get_global_id(0); - unsigned int globalPosY = get_global_id(1); - unsigned int globalPosZ = get_global_id(2); - - unsigned short outputS = get_global_size(1); - unsigned short outputL = get_global_size(0); - - // get image width and weight - const unsigned int inputL = get_image_width( dSource ); - const unsigned int inputS = get_image_height( dSource ); - const unsigned int Slices = get_image_depth( dSource ); - - // create an image sampler - const sampler_t defaultSampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST ; - - // terminate non-valid threads - if ( globalPosX < outputL && globalPosY < outputS && globalPosZ < Slices ) - { - float l_i = (float)globalPosX / outputL * inputL; - float s_i = (float)globalPosY / outputS * inputS / 2; - - float part = (tan(Angle / 360 * 2 * M_PI) * TimeSpacing * SpeedOfSound / Pitch * outputL / TransducerElements) * s_i; - if (part < 1) - part = 1; - - short maxLine = min((l_i + part) + 1, (float)inputL); - short minLine = max((l_i - part), 0.0f); - short usedLines = (maxLine - minLine); - float apod_mult = apodArraySize / (maxLine - minLine); - - float mult = 0; - float output = 0; - float AddSample1 = 0; - float AddSample2 = 0; - - for (short l_s1 = minLine; l_s1 < maxLine - 1; ++l_s1) - { - AddSample1 = sqrt( - pow(s_i, 2) - + - pow((1 / (TimeSpacing*SpeedOfSound) * ((l_s1 - l_i)*Pitch*TransducerElements)/inputL), 2) - ) + (1-PAImage)*s_i; - if (AddSample1 < inputS && AddSample1 >= 0) - { - for (short l_s2 = l_s1 + 1; l_s2 < maxLine; ++l_s2) - { - AddSample2 = sqrt( - pow(s_i, 2) - + - pow((1 / (TimeSpacing*SpeedOfSound) * ((l_s2 - l_i)*Pitch*TransducerElements)/inputL), 2) - ) + (1-PAImage)*s_i; - if (AddSample2 < inputS && AddSample2 >= 0) - { - mult = read_imagef( dSource, defaultSampler, (int4)(l_s2, AddSample2, globalPosZ, 0 )).x - * apodArray[(short)((l_s2 - minLine)*apod_mult)] - * read_imagef( dSource, defaultSampler, (int4)(l_s1, AddSample1, globalPosZ, 0 )).x - * apodArray[(short)((l_s1 - minLine)*apod_mult)]; - output += sqrt(mult * ((float)(mult>0)-(float)(mult<0))) * ((mult > 0) - (mult < 0)); - } - } - } - else - --usedLines; - } - - dDest[ globalPosZ * outputL * outputS + globalPosY * outputL + globalPosX ] = 10 * output / (pow((float)usedLines, 2.0f) - (usedLines - 1)); - } -} \ No newline at end of file diff --git a/Modules/PhotoacousticsAlgorithms/Resources/DelayCalculation.cl b/Modules/PhotoacousticsAlgorithms/Resources/DelayCalculation.cl new file mode 100644 index 0000000000..0be471b2b4 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Resources/DelayCalculation.cl @@ -0,0 +1,69 @@ +/*=================================================================== + +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. + +===================================================================*/ + +__kernel void ckDelayCalculationQuad( __global unsigned short *gDest, + __global unsigned short *usedLines, + unsigned int inputL, + unsigned int inputS, + unsigned int outputL, + unsigned int outputS, + char isPAImage, + float delayMultiplicatorRaw // parameters + ) +{ + uint globalPosX = get_global_id(0); + uint globalPosY = get_global_id(1); + + if (globalPosX * 2 < outputL && globalPosY < outputS) + { + float l_i = 0; // we calculate the delays relative to line zero + float s_i = (float)globalPosY / (float)outputS * (float)inputS / 2; + + float l_s = (float)globalPosX / (float)outputL * (float)inputL; // the currently calculated line + + float delayMultiplicator = delayMultiplicatorRaw / s_i; + gDest[globalPosY * (outputL / 2) + globalPosX] = delayMultiplicator * pow((l_s - l_i), 2) + s_i + (1-isPAImage)*s_i; + } +} + +__kernel void ckDelayCalculationSphe( __global unsigned short *gDest, + __global unsigned short *usedLines, + unsigned int inputL, + unsigned int inputS, + unsigned int outputL, + unsigned int outputS, + char isPAImage, + float delayMultiplicatorRaw // parameters + ) +{ + uint globalPosX = get_global_id(0); + uint globalPosY = get_global_id(1); + + if (globalPosX * 2 < outputL && globalPosY < outputS) + { + float l_i = 0; // we calculate the delays relative to line zero + float s_i = (float)globalPosY / (float)outputS * (float)inputS / 2; + + float l_s = (float)globalPosX / (float)outputL * (float)inputL; // the currently calculated line + + gDest[globalPosY * (outputL / 2) + globalPosX] = + sqrt( + pow(s_i, 2) + + + pow((delayMultiplicatorRaw * ((l_s - l_i)) / inputL), 2) + ) + (1-isPAImage)*s_i; + } +} \ No newline at end of file diff --git a/Modules/PhotoacousticsAlgorithms/Resources/UsedLinesCalculation.cl b/Modules/PhotoacousticsAlgorithms/Resources/UsedLinesCalculation.cl new file mode 100644 index 0000000000..638de2b279 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Resources/UsedLinesCalculation.cl @@ -0,0 +1,50 @@ +/*=================================================================== + +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. + +===================================================================*/ + +__kernel void ckUsedLines( + __global unsigned short* dDest, // output buffer + float partMult, + unsigned int inputL, + unsigned int inputS, + unsigned int outputL, + unsigned int outputS +) +{ + // get thread identifier + unsigned int globalPosX = get_global_id(0); + unsigned int globalPosY = get_global_id(1); + + //unsigned short outputS = get_global_size(1); + //unsigned short outputL = get_global_size(0); + + // terminate non-valid threads + if ( globalPosX < outputL && globalPosY < outputS) + { + float l_i = (float)globalPosX / outputL * inputL; + float s_i = (float)globalPosY / outputS * inputS / 2; + + float part = partMult * s_i; + if (part < 1) + part = 1; + + unsigned short maxLine = min((l_i + part) + 1, (float)inputL); + unsigned short minLine = max((l_i - part), 0.0f); + + dDest[globalPosY * 3 * outputL + 3 * globalPosX] = (maxLine - minLine); //usedLines + dDest[globalPosY * 3 * outputL + 3 * globalPosX + 1] = minLine; //minLine + dDest[globalPosY * 3 * outputL + 3 * globalPosX + 2] = maxLine; //maxLine + } +} \ No newline at end of file diff --git a/Modules/PhotoacousticsAlgorithms/Resources/sDMAS.cl b/Modules/PhotoacousticsAlgorithms/Resources/sDMAS.cl new file mode 100644 index 0000000000..b362047846 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Resources/sDMAS.cl @@ -0,0 +1,87 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +__kernel void cksDMAS( + __global float* dSource, // input image + __global float* dDest, // output buffer + __global unsigned short* usedLines, + __global unsigned short* AddSamples, + __constant float* apodArray, + unsigned short apodArraySize, + unsigned int inputL, + unsigned int inputS, + unsigned int Slices, + unsigned int outputL, + unsigned int outputS // parameters +) +{ + // get thread identifier + unsigned int globalPosX = get_global_id(0); + unsigned int globalPosY = get_global_id(1); + unsigned int globalPosZ = get_global_id(2); + + // terminate non-valid threads + if ( globalPosX < outputL && globalPosY < outputS && globalPosZ < Slices ) + { + float l_i = (float)globalPosX / (float)outputL * (float)inputL; + + unsigned short curUsedLines = usedLines[globalPosY * 3 * outputL + 3 * globalPosX]; + unsigned short minLine = usedLines[globalPosY * 3 * outputL + 3 * globalPosX + 1]; + unsigned short maxLine = usedLines[globalPosY * 3 *outputL + 3 * globalPosX + 2]; + + float apod_mult = (float)apodArraySize / (float)curUsedLines; + + unsigned short Delay1 = 0; + unsigned short Delay2 = 0; + + float output = 0; + float mult = 0; + + float s_1 = 0; + float s_2 = 0; + float sign = 0; + float apod_1 = 0; + + for (short l_s1 = minLine; l_s1 < maxLine; ++l_s1) + { + Delay1 = AddSamples[globalPosY * (outputL / 2) + (int)(fabs(l_s1 - l_i)/(float)inputL * (float)outputL)]; + if (Delay1 < inputS && Delay1 >= 0) + { + s_1 = dSource[(int)(globalPosZ * inputL * inputS + Delay1 * inputL + l_s1)]; + apod_1 = apodArray[(int)((l_s1 - minLine)*apod_mult)]; + sign += s_1; + + for (short l_s2 = l_s1 + 1; l_s2 < maxLine; ++l_s2) + { + Delay2 = AddSamples[globalPosY * (outputL / 2) + (int)(fabs(l_s2 - l_i)/(float)inputL * (float)outputL)]; + if (Delay2 < inputS && Delay2 >= 0) + { + s_2 = dSource[(int)(globalPosZ * inputL * inputS + Delay2 * inputL + l_s2)]; + + mult = apodArray[(int)((l_s2 - minLine)*apod_mult)] * s_2 + * apod_1 * s_1; + + output += sqrt(fabs(mult)) * ((mult > 0) - (mult < 0)); + } + } + } + else + --curUsedLines; + } + + dDest[ globalPosZ * outputL * outputS + globalPosY * outputL + globalPosX ] = output / (float)(curUsedLines * curUsedLines - (curUsedLines - 1)) * ((sign > 0) - (sign < 0)); + } +} diff --git a/Modules/PhotoacousticsAlgorithms/files.cmake b/Modules/PhotoacousticsAlgorithms/files.cmake index 08f72362af..b3fdaff026 100644 --- a/Modules/PhotoacousticsAlgorithms/files.cmake +++ b/Modules/PhotoacousticsAlgorithms/files.cmake @@ -1,18 +1,25 @@ +file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") + set(CPP_FILES - mitkPhotoacousticImage.cpp - - Algorithms/mitkPhotoacousticBeamformingFilter.cpp - - Algorithms/OCL/mitkPhotoacousticOCLBeamformer.cpp - - Algorithms/OCL/mitkPhotoacousticBModeFilter.cpp + source/mitkPhotoacousticImage.cpp + source/mitkPhotoacousticBeamformingFilter.cpp + source/OpenCLFilter/mitkPhotoacousticBModeFilter.cpp +) + +IF(MITK_USE_OpenCL) +list(APPEND CPP_FILES + source/OpenCLFilter/mitkPhotoacousticOCLBeamformingFilter.cpp + source/OpenCLFilter/mitkPhotoacousticOCLUsedLinesCalculation.cpp + source/OpenCLFilter/mitkPhotoacousticOCLDelayCalculation.cpp ) +ENDIF(MITK_USE_OpenCL) set(RESOURCE_FILES - DASQuadratic.cl - DMASQuadratic.cl - DASspherical.cl - DMASspherical.cl BModeAbs.cl BModeAbsLog.cl -) \ No newline at end of file + UsedLinesCalculation.cl + DelayCalculation.cl + DMAS.cl + DAS.cl + sDMAS.cl +) diff --git a/Modules/PhotoacousticsAlgorithms/include/OpenCLFilter/mitkPhotoacousticBModeFilter.h b/Modules/PhotoacousticsAlgorithms/include/OpenCLFilter/mitkPhotoacousticBModeFilter.h new file mode 100644 index 0000000000..aa98d0fc37 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/include/OpenCLFilter/mitkPhotoacousticBModeFilter.h @@ -0,0 +1,140 @@ +/*=================================================================== + +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 _MITKPHOTOACOUSTICSBMODEFILTER_H_ +#define _MITKPHOTOACOUSTICSBMODEFILTER_H_ + +#if defined(PHOTOACOUSTICS_USE_GPU) || DOXYGEN +#include "mitkOclDataSetToDataSetFilter.h" +#endif + +#include +#include "mitkImageToImageFilter.h" + +namespace mitk +{ + #if defined(PHOTOACOUSTICS_USE_GPU) || DOXYGEN + + /*! + * \brief Class implementing a mitk::OclDataSetToDataSetFilter for BMode filtering on GPU + * + * The only parameter that needs to be provided is whether it should use a logfilter. + * Currently this class only performs an absolute BMode filter. + */ + class PhotoacousticOCLBModeFilter : public OclDataSetToDataSetFilter, public itk::Object + { + + public: + mitkClassMacroItkParent(PhotoacousticOCLBModeFilter, itk::Object); + itkNewMacro(Self); + + /** \brief Set the input image to be processed + */ + void SetInput(Image::Pointer image); + + void Update(); + + /** \brief Set parameters for the filter + * + * @param useLogFilter If true, the filter will apply a logfilter on the processed image + */ + void SetParameters(bool useLogFilter) + { + m_UseLogFilter = useLogFilter; + } + + /** + * @brief GetOutput Returns an mitk::Image constructed from the processed data + */ + mitk::Image::Pointer GetOutput(); + + protected: + + PhotoacousticOCLBModeFilter(); + + virtual ~PhotoacousticOCLBModeFilter(); + + bool Initialize(); + + void Execute(); + + mitk::PixelType GetOutputType() + { + return mitk::MakeScalarPixelType(); + } + + int GetBytesPerElem() + { + return sizeof(float); + } + + virtual us::Module* GetModule(); + + private: + /** The OpenCL kernel for the filter */ + cl_kernel m_PixelCalculation; + bool m_UseLogFilter; + + mitk::Image::Pointer m_InputImage; + unsigned int m_InputDim[3]; + unsigned int m_Size; + + }; + #endif + + /*! + * \brief Class implementing a mitk::ImageToImageFilter for BMode filtering on CPU + * + * The only parameter that needs to be provided is whether it should use a logfilter. + * Currently this class only performs an absolute BMode filter. + */ + class PhotoacousticBModeFilter : public ImageToImageFilter + { + public: + mitkClassMacro(PhotoacousticBModeFilter, ImageToImageFilter); + + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + + /** \brief Set parameters for the filter + * + * @param useLogFilter If true, the filter will apply a logfilter on the processed image + */ + void SetParameters(bool useLogFilter) + { + m_UseLogFilter = useLogFilter; + } + + protected: + + PhotoacousticBModeFilter(); + + ~PhotoacousticBModeFilter(); + + virtual void GenerateInputRequestedRegion() override; + + virtual void GenerateOutputInformation() override; + + virtual void GenerateData() override; + + //##Description + //## @brief Time when Header was last initialized + itk::TimeStamp m_TimeOfHeaderInitialization; + + bool m_UseLogFilter; + }; +} +#endif diff --git a/Modules/PhotoacousticsAlgorithms/include/OpenCLFilter/mitkPhotoacousticOCLBeamformingFilter.h b/Modules/PhotoacousticsAlgorithms/include/OpenCLFilter/mitkPhotoacousticOCLBeamformingFilter.h new file mode 100644 index 0000000000..78ced9688a --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/include/OpenCLFilter/mitkPhotoacousticOCLBeamformingFilter.h @@ -0,0 +1,154 @@ +/*=================================================================== + +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 _MITKPHOTOACOUSTICSOCLBEAMFORMER_H_ +#define _MITKPHOTOACOUSTICSOCLBEAMFORMER_H_ + +#include + +#if defined(PHOTOACOUSTICS_USE_GPU) || DOXYGEN + +#include "mitkOclDataSetToDataSetFilter.h" + +#include "mitkPhotoacousticOCLDelayCalculation.h" +#include "mitkPhotoacousticOCLUsedLinesCalculation.h" +#include "mitkPhotoacousticBeamformingSettings.h" + +#include + +namespace mitk +{ + /*! + * \brief Class implementing a mitk::OclDataSetToDataSetFilter for beamforming on GPU + * + * The class must be given a configuration class instance of mitk::BeamformingSettings for beamforming parameters through mitk::PhotoacousticOCLBeamformingFilter::SetConfig(BeamformingSettings settings) + * Additional configuration of the apodisation function is needed. + */ + +class PhotoacousticOCLBeamformingFilter : public OclDataSetToDataSetFilter, public itk::Object +{ + +public: + mitkClassMacroItkParent(PhotoacousticOCLBeamformingFilter, itk::Object); + itkNewMacro(Self); + + /** + * @brief SetInput Set the input data through an image. Arbitrary images are supported + */ + void SetInput(Image::Pointer image); + /** + * brief SetInput Manually set the input data while providing 3 dimensions and memory size of the input data (Bytes per element). + */ + void SetInput(void* data, unsigned int* dimensions, unsigned int BpE); + /** + * @brief GetOutput Get a pointer to the processed data. The standard datatype is float. + */ + void* GetOutput(); + + /** + * @brief GetOutputAsImage Returns an mitk::Image constructed from the processed data + */ + mitk::Image::Pointer GetOutputAsImage(); + + /** \brief Update the filter */ + void Update(); + + /** \brief Set the Apodisation function to apply when beamforming */ + void SetApodisation(float* apodisation, unsigned short apodArraySize) + { + m_ApodArraySize = apodArraySize; + m_Apodisation = apodisation; + } + + /** \brief Set beamforming settings to use when beamforming */ + void SetConfig(BeamformingSettings settings) + { + m_ConfOld = m_Conf; + m_Conf = settings; + } + +protected: + + PhotoacousticOCLBeamformingFilter(); + virtual ~PhotoacousticOCLBeamformingFilter(); + + /** \brief Initialize the filter */ + bool Initialize(); + + /** \brief Updated the used data for beamforming depending on whether the configuration has significantly changed */ + void UpdateDataBuffers(); + + /** \brief Execute the filter */ + void Execute(); + + mitk::PixelType GetOutputType() + { + return mitk::MakeScalarPixelType(); + } + + int GetBytesPerElem() + { + return sizeof(float); + } + + virtual us::Module* GetModule(); + +private: + /** The OpenCL kernel for the filter */ + cl_kernel m_PixelCalculation; + + unsigned int m_OutputDim[3]; + + float* m_Apodisation; + unsigned short m_ApodArraySize; + + unsigned short m_PAImage; + + BeamformingSettings m_Conf; + BeamformingSettings m_ConfOld; + + mitk::Image::Pointer m_InputImage; + + size_t m_ChunkSize[3]; + + mitk::OCLUsedLinesCalculation::Pointer m_UsedLinesCalculation; + mitk::OCLDelayCalculation::Pointer m_DelayCalculation; + + cl_mem m_ApodizationBuffer; + cl_mem m_MemoryLocationsBuffer; + cl_mem m_DelaysBuffer; + cl_mem m_UsedLinesBuffer; +}; +} +#else +namespace mitk +{ + class PhotoacousticOCLBeamformingFilter : public itk::Object + { + public: + mitkClassMacroItkParent(mitk::PhotoacousticOCLBeamformingFilter, itk::Object); + itkNewMacro(Self); + + protected: + /** Constructor */ + PhotoacousticOCLBeamformingFilter() {} + + /** Destructor */ + virtual ~PhotoacousticOCLBeamformingFilter() {} + }; +} +#endif +#endif diff --git a/Modules/PhotoacousticsAlgorithms/include/OpenCLFilter/mitkPhotoacousticOCLDelayCalculation.h b/Modules/PhotoacousticsAlgorithms/include/OpenCLFilter/mitkPhotoacousticOCLDelayCalculation.h new file mode 100644 index 0000000000..061f7c7448 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/include/OpenCLFilter/mitkPhotoacousticOCLDelayCalculation.h @@ -0,0 +1,99 @@ +/*=================================================================== + +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 _MITKPHOTOACOUSTICSDELAYCALC_H_ +#define _MITKPHOTOACOUSTICSDELAYCALC_H_ + +#if defined(PHOTOACOUSTICS_USE_GPU) || DOXYGEN + +#include "mitkOclDataSetToDataSetFilter.h" +#include +#include "mitkPhotoacousticBeamformingSettings.h" + +namespace mitk +{ + /*! + * \brief Class implementing a mitk::OclDataSetToDataSetFilter to calculate the delays used for beamforming. + * + * The class must be given a configuration class instance of mitk::BeamformingSettings for beamforming parameters through mitk::OCLDelayCalculation::SetConfig(BeamformingSettings conf) + * Additionally the output of an instance of mitk::OCLUsedLinesCalculation is needed to calculate the delays. + */ + + class OCLDelayCalculation : public OclDataSetToDataSetFilter, public itk::Object + { + + public: + mitkClassMacroItkParent(OCLDelayCalculation, itk::Object); + itkNewMacro(Self); + + void Update(); + + /** \brief Sets a new configuration to use. + * + * @param conf The configuration set to use for the calculation of the delays. + */ + void SetConfig(BeamformingSettings conf) + { + m_Conf = conf; + } + + /** \brief Sets the usedLines buffer object to use for the calculation of the delays. + * + * @param usedLines An buffer generated as the output of an instance of mitk::OCLUsedLinesCalculation. + */ + void SetInputs(cl_mem usedLines) + { + m_UsedLines = usedLines; + } + + protected: + + OCLDelayCalculation(); + virtual ~OCLDelayCalculation(); + + /** Initialize the filter */ + bool Initialize(); + + void Execute(); + + mitk::PixelType GetOutputType() + { + return mitk::MakeScalarPixelType(); + } + + int GetBytesPerElem() + { + return sizeof(unsigned short); + } + + virtual us::Module* GetModule(); + + int m_sizeThis; + + private: + /** The OpenCL kernel for the filter */ + cl_kernel m_PixelCalculation; + + BeamformingSettings m_Conf; + cl_mem m_UsedLines; + unsigned int m_BufferSize; + float m_DelayMultiplicatorRaw; + char m_IsPAImage; + size_t m_ChunkSize[3]; + }; +} +#endif +#endif \ No newline at end of file diff --git a/Modules/PhotoacousticsAlgorithms/include/OpenCLFilter/mitkPhotoacousticOCLUsedLinesCalculation.h b/Modules/PhotoacousticsAlgorithms/include/OpenCLFilter/mitkPhotoacousticOCLUsedLinesCalculation.h new file mode 100644 index 0000000000..e787d2009a --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/include/OpenCLFilter/mitkPhotoacousticOCLUsedLinesCalculation.h @@ -0,0 +1,90 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef _MITKPHOTOACOUSTICSOCLUSEDLINESCALCULATION_H_ +#define _MITKPHOTOACOUSTICSOCLUSEDLINESCALCULATION_H_ + +#if defined(PHOTOACOUSTICS_USE_GPU) || DOXYGEN + +#include "mitkOclDataSetToDataSetFilter.h" +#include +#include "mitkPhotoacousticBeamformingSettings.h" + +namespace mitk +{ + /*! + * \brief Class implementing a mitk::OclDataSetToDataSetFilter to calculate which lines each sample should use when beamforming. + * + * The class must be given a configuration class instance of mitk::BeamformingSettings for beamforming parameters through mitk::OCLDelayCalculation::SetConfig(BeamformingSettings conf) + */ + + class OCLUsedLinesCalculation : public OclDataSetToDataSetFilter, public itk::Object + { + + public: + mitkClassMacroItkParent(OCLUsedLinesCalculation, itk::Object); + itkNewMacro(Self); + + void Update(); + + /** \brief Sets a new configuration to use. + * + * @param conf The configuration set to use for the calculation of the used lines. + */ + void SetConfig(BeamformingSettings conf) + { + m_Conf = conf; + } + + protected: + + /** Constructor */ + OCLUsedLinesCalculation(); + + /** Destructor */ + virtual ~OCLUsedLinesCalculation(); + + /** Initialize the filter */ + bool Initialize(); + + void Execute(); + + mitk::PixelType GetOutputType() + { + return mitk::MakeScalarPixelType(); + } + + int GetBytesPerElem() + { + return sizeof(unsigned short); + } + + virtual us::Module* GetModule(); + + int m_sizeThis; + + + private: + /** The OpenCL kernel for the filter */ + cl_kernel m_PixelCalculation; + + BeamformingSettings m_Conf; + float m_part; + size_t m_ChunkSize[3]; + }; +} +#endif +#endif diff --git a/Modules/PhotoacousticsAlgorithms/include/mitkPhotoacousticBeamformingFilter.h b/Modules/PhotoacousticsAlgorithms/include/mitkPhotoacousticBeamformingFilter.h new file mode 100644 index 0000000000..214ef84e5d --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/include/mitkPhotoacousticBeamformingFilter.h @@ -0,0 +1,151 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef MITK_PHOTOACOUSTICS_BEAMFORMING_FILTER +#define MITK_PHOTOACOUSTICS_BEAMFORMING_FILTER + +#include "mitkImageToImageFilter.h" +#include +#include "./OpenCLFilter/mitkPhotoacousticOCLBeamformingFilter.h" +#include "mitkPhotoacousticBeamformingSettings.h" + +namespace mitk { + /*! + * \brief Class implementing an mitk::ImageToImageFilter for beamforming on both CPU and GPU + * + * The class must be given a configuration class instance of mitk::BeamformingSettings for beamforming parameters through mitk::BeamformingFilter::Configure(BeamformingSettings settings) + * Whether the GPU is used can be set in the configuration. + * For significant problems or important messages a string is written, which can be accessed via GetMessageString(). + */ + + class BeamformingFilter : public ImageToImageFilter + { + public: + mitkClassMacro(BeamformingFilter, ImageToImageFilter); + + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + + /** \brief Sets a new configuration to use + * + * @param settings The configuration set to use for beamforming + */ + void Configure(BeamformingSettings settings) + { + m_ConfOld = m_Conf; + m_Conf = settings; + } + + /** \brief Sets a new configuration to use + * + * The Filter writes important messages that can be retrieved through this method; if nothing is to be reported, it returns "noMessage". + * @return The message + */ + std::string GetMessageString() + { + return m_Message; + } + + /** \brief Sets a callback for progress checking + * + * An std::function can be set, through which progress of the currently updating filter is reported. + * The integer argument is a number between 0 an 100 to indicate how far completion has been achieved, the std::string argument indicates what the filter is currently doing. + */ + void SetProgressHandle(std::function progressHandle); + + protected: + BeamformingFilter(); + + ~BeamformingFilter(); + + virtual void GenerateInputRequestedRegion() override; + + virtual void GenerateOutputInformation() override; + + virtual void GenerateData() override; + + //##Description + //## @brief Time when Header was last initialized + itk::TimeStamp m_TimeOfHeaderInitialization; + + /** \brief The std::function, through which progress of the currently updating filter is reported. + */ + std::function m_ProgressHandle; + + /** \brief Pointer holding the Von-Hann apodization window for beamforming + * @param samples the resolution at which the window is created + */ + float* VonHannFunction(int samples); + /** \brief Function to create a Hamming apodization window + * @param samples the resolution at which the window is created + */ + float* HammFunction(int samples); + /** \brief Function to create a Box apodization window + * @param samples the resolution at which the window is created + */ + float* BoxFunction(int samples); + + /** \brief Function to perform beamforming on CPU for a single line, using DAS and quadratic delay + */ + void DASQuadraticLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize); + /** \brief Function to perform beamforming on CPU for a single line, using DAS and spherical delay + */ + void DASSphericalLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize); + /** \brief Function to perform beamforming on CPU for a single line, using DMAS and quadratic delay + */ + void DMASQuadraticLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize); + /** \brief Function to perform beamforming on CPU for a single line, using DMAS and spherical delay + */ + void DMASSphericalLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize); + /** \brief Function to perform beamforming on CPU for a single line, using signed DMAS and quadratic delay + */ + void sDMASQuadraticLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize); + /** \brief Function to perform beamforming on CPU for a single line, using signed DMAS and spherical delay + */ + void sDMASSphericalLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize); + + float* m_OutputData; + float* m_InputData; + float* m_InputDataPuffer; + + /** \brief Pointer holding the Von-Hann apodization window for beamforming + */ + float* m_VonHannFunction; + /** \brief Pointer holding the Hamming apodization window for beamforming + */ + float* m_HammFunction; + /** \brief Pointer holding the Box apodization window for beamforming + */ + float* m_BoxFunction; + + /** \brief Current configuration set + */ + BeamformingSettings m_Conf; + /** \brief Previous configuration set to selectively update used data for beamforming + */ + BeamformingSettings m_ConfOld; + + /** \brief Pointer to the GPU beamforming filter class; for performance reasons the filter is initialized within the constructor and kept for all later computations. + */ + mitk::PhotoacousticOCLBeamformingFilter::Pointer m_BeamformingOclFilter; + + /** \brief The message returned by mitk::BeamformingFilter::GetMessageString() + */ + std::string m_Message; + }; +} // namespace mitk + +#endif //MITK_PHOTOACOUSTICS_BEAMFORMING_FILTER diff --git a/Modules/PhotoacousticsAlgorithms/include/mitkPhotoacousticBeamformingSettings.h b/Modules/PhotoacousticsAlgorithms/include/mitkPhotoacousticBeamformingSettings.h new file mode 100644 index 0000000000..a48b5e78a3 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/include/mitkPhotoacousticBeamformingSettings.h @@ -0,0 +1,137 @@ +/*=================================================================== + +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_PHOTOACOUSTICS_BEAMFORMING_SETTINGS +#define MITK_PHOTOACOUSTICS_BEAMFORMING_SETTINGS + + + +namespace mitk { + /*! + * \brief Class holding the configuration data for the beamforming filters mitk::BeamformingFilter and mitk::PhotoacousticOCLBeamformingFilter + * + * A detailed description can be seen below. All parameters should be set manually for successfull beamforming. + */ + + class BeamformingSettings + { + public: + /** \brief Pitch of the used transducer in [m]. + */ + float Pitch = 0.0003; + /** \brief Speed of sound in the used medium in [m/s]. + */ + float SpeedOfSound = 1540; + /** \brief This parameter is not neccessary to be set, as it's never used. + */ + float RecordTime = 0.00006; // [s] + /** \brief The time spacing of the input image + */ + float TimeSpacing = 0.0000000000001; // [s] + /** \brief The angle of the transducer elements + */ + float Angle = -1; + /** \brief Flag whether processed image is a photoacoustic image or an ultrasound image + */ + bool isPhotoacousticImage = true; + + /** \brief How many transducer elements the used transducer had. + */ + unsigned short TransducerElements = 128; + /** \brief How many vertical samples should be used in the final image. + */ + unsigned int SamplesPerLine = 2048; + /** \brief How many lines should be reconstructed in the final image. + */ + unsigned int ReconstructionLines = 128; + /** \brief Sets how many voxels should be cut off from the top of the image before beamforming, to potentially avoid artifacts. + */ + unsigned int upperCutoff = 0; + /** \brief Sets whether only the slices selected by mitk::BeamformingSettings::CropBounds should be beamformed. + */ + bool partial = false; + /** \brief Sets the first and last slice to be beamformed. + */ + unsigned int CropBounds[2] = { 0,0 }; + /** \brief Sets the dimensions of the inputImage. + */ + unsigned int inputDim[3] = { 1,1,1 }; + + /** \brief Decides whether GPU computing should be used + */ + bool UseGPU = true; + + /** \brief Available delay calculation methods: + * - Spherical delay for best results. + * - A quadratic Taylor approximation for slightly faster results with hardly any quality loss. + */ + enum DelayCalc { QuadApprox, Spherical }; + /** \brief Sets how the delays for beamforming should be calculated. + */ + DelayCalc DelayCalculationMethod = QuadApprox; + + /** \brief Available apodization functions: + * - Hamming function. + * - Von-Hann function. + * - Box function. + */ + enum Apodization { Hamm, Hann, Box }; + /** \brief Sets the used apodization function. + */ + Apodization Apod = Hann; + /** \brief Sets the resolution of the apodization array (must be greater than 0). + */ + int apodizationArraySize = 128; + + /** \brief Available beamforming algorithms: + * - DAS (Delay and sum). + * - DMAS (Delay multiply and sum). + */ + enum BeamformingAlgorithm { DMAS, DAS, sDMAS}; + /** \brief Sets the used beamforming algorithm. + */ + BeamformingAlgorithm Algorithm = DAS; + + /** \brief Sets whether after beamforming a bandpass should be automatically applied + */ + bool UseBP = false; + /** \brief Sets the position at which lower frequencies are completely cut off in Hz. + */ + float BPHighPass = 50; + /** \brief Sets the position at which higher frequencies are completely cut off in Hz. + */ + float BPLowPass = 50; + + /** \brief function for mitk::PhotoacousticOCLBeamformingFilter to check whether buffers need to be updated + * this method only checks parameters relevant for the openCL implementation + */ + static bool SettingsChangedOpenCL(const BeamformingSettings& lhs, const BeamformingSettings& rhs) + { + return !((abs(lhs.Angle - rhs.Angle) < 0.01f) && // 0.01 degree error margin + (lhs.Apod == rhs.Apod) && + (lhs.DelayCalculationMethod == rhs.DelayCalculationMethod) && + (lhs.isPhotoacousticImage == rhs.isPhotoacousticImage) && + (abs(lhs.Pitch - rhs.Pitch) < 0.000001f) && // 0.0001 mm error margin + (lhs.ReconstructionLines == rhs.ReconstructionLines) && + (abs(lhs.RecordTime - rhs.RecordTime) < 0.00000001f) && // 10 ns error margin + (lhs.SamplesPerLine == rhs.SamplesPerLine) && + (abs(lhs.SpeedOfSound - rhs.SpeedOfSound) < 0.01f) && + (abs(lhs.TimeSpacing - rhs.TimeSpacing) < 0.00000000001f) && //0.01 ns error margin + (lhs.TransducerElements == rhs.TransducerElements)); + } + }; +} +#endif \ No newline at end of file diff --git a/Modules/PhotoacousticsAlgorithms/include/mitkPhotoacousticImage.h b/Modules/PhotoacousticsAlgorithms/include/mitkPhotoacousticImage.h new file mode 100644 index 0000000000..b92fb58ade --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/include/mitkPhotoacousticImage.h @@ -0,0 +1,125 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef mitkPhotoacousticImage_H_HEADER_INCLUDED +#define mitkPhotoacousticImage_H_HEADER_INCLUDED + +#include "itkObject.h" +#include "mitkCommon.h" +#include "mitkImage.h" +#include + +#include "mitkPhotoacousticBeamformingSettings.h" +#include "mitkPhotoacousticBeamformingFilter.h" +#include "MitkPhotoacousticsAlgorithmsExports.h" + +namespace mitk { + /*! + * \brief Class holding methods to apply all Filters within the Photoacoustics Algorithms Module + * + * Implemented are: + * - A B-Mode Filter + * - A Resampling Filter + * - Beamforming on GPU and CPU + * - A Bandpass Filter + */ + + class MITKPHOTOACOUSTICSALGORITHMS_EXPORT PhotoacousticImage : public itk::Object + { + public: + mitkClassMacroItkParent(mitk::PhotoacousticImage, itk::Object); + itkFactorylessNewMacro(Self); + /** \brief Defines the methods for the B-Mode filter + * Currently implemented are an Envelope Detection filter and a simple Absolute filter. + */ + enum BModeMethod { EnvelopeDetection, Abs }; + + /** \brief Applies a B-Mode Filter + * + * Applies a B-Mode filter using the given parameters. + * @param inputImage The image to be processed. + * @param method The kind of B-Mode Filter to be used. + * @param UseGPU Setting this to true will allow the Filter to use the GPU. + * @param UseLogFilter Setting this to true will apply a simple logarithm to the image after the B-Mode Filter has been applied. + * @param resampleSpacing If this is set to 0, nothing will be done; otherwise, the image is resampled to a spacing of resampleSpacing mm per pixel. + * @return The processed image is returned after the filter has finished. + */ + mitk::Image::Pointer ApplyBmodeFilter(mitk::Image::Pointer inputImage, BModeMethod method = BModeMethod::Abs, bool UseGPU = false, bool UseLogFilter = false, float resampleSpacing = 0.15); + + // mitk::Image::Pointer ApplyScatteringCompensation(mitk::Image::Pointer inputImage, int scatteringCoefficient); + + /** \brief Resamples the given image + * + * Resamples an image using the given parameters. + * @param inputImage The image to be processed. + * @param outputSize An array of dimensions the image should be resampled to. + * @return The processed image is returned after the filter has finished. + */ + mitk::Image::Pointer ApplyResampling(mitk::Image::Pointer inputImage, unsigned int outputSize[2]); + + /** \brief Beamforms the given image + * + * Resamples an image using the given parameters. + * @param inputImage The image to be processed. + * @param config The configuration set to be used for beamforming. + * @param message A string into which potentially critical messages will be written. + * @param progressHandle An std::function, through which progress of the currently updating filter is reported. + * The integer argument is a number between 0 an 100 to indicate how far completion has been achieved, the std::string argument indicates what the filter is currently doing. + * @return The processed image is returned after the filter has finished. + */ + mitk::Image::Pointer ApplyBeamforming(mitk::Image::Pointer inputImage, BeamformingSettings config, std::string& message, std::function progressHandle = [](int, std::string) {}); + + /** \brief Crops the given image + * + * Crops an image in 3 dimension using the given parameters. + * @param inputImage The image to be processed. + * @param above How many voxels will be cut from the top of the image. + * @param below How many voxels will be cut from the bottom of the image. + * @param right How many voxels will be cut from the right side of the image. + * @param left How many voxels will be cut from the left side of the image. + * @param minSlice The first slice to be present in the resulting image. + * @param maxSlice The last slice to be present in the resulting image. + * @return The processed image is returned after the filter has finished. For the purposes of this module, the returned image is always of type float. + */ + mitk::Image::Pointer ApplyCropping(mitk::Image::Pointer inputImage, int above, int below, int right, int left, int minSlice, int maxSlice); + + /** \brief Applies a Bandpass filter to the given image + * + * Applies a bandpass filter to the given image using the given parameters. + * @param data The image to be processed. + * @param recordTime The depth of the image in seconds. + * @param BPHighPass The position at which Lower frequencies are completely cut off in Hz. + * @param BPLowPass The position at which Higher frequencies are completely cut off in Hz. + * @param alpha The tukey window parameter to control the shape of the bandpass filter: 0 will make it a Box function, 1 a Hann function. alpha can be set between those two bounds. + * @return The processed image is returned after the filter has finished. + */ + mitk::Image::Pointer BandpassFilter(mitk::Image::Pointer data, float recordTime, float BPHighPass, float BPLowPass, float alpha); + + protected: + PhotoacousticImage(); + virtual ~PhotoacousticImage(); + + /** \brief For performance reasons, an instance of the Beamforming filter is initialized as soon as possible and kept for all further uses. + */ + mitk::BeamformingFilter::Pointer m_BeamformingFilter; + + /** \brief Function that creates a Tukey function for the bandpass + */ + itk::Image::Pointer BPFunction(mitk::Image::Pointer reference, int cutoffFrequencyPixelHighPass, int cutoffFrequencyPixelLowPass, float alpha); + }; +} // namespace mitk + +#endif /* mitkPhotoacousticImage_H_HEADER_INCLUDED */ diff --git a/Modules/PhotoacousticsAlgorithms/mitkPhotoacousticImage.cpp b/Modules/PhotoacousticsAlgorithms/mitkPhotoacousticImage.cpp index 9ba451e9cd..08f92552bc 100644 --- a/Modules/PhotoacousticsAlgorithms/mitkPhotoacousticImage.cpp +++ b/Modules/PhotoacousticsAlgorithms/mitkPhotoacousticImage.cpp @@ -1,641 +1,522 @@ /*=================================================================== 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 #include "mitkPhotoacousticImage.h" -#include "itkBModeImageFilter.h" -#include "itkPhotoacousticBModeImageFilter.h" +#include "ITKFilter/ITKUltrasound/itkBModeImageFilter.h" +#include "ITKFilter/itkPhotoacousticBModeImageFilter.h" #include "mitkImageCast.h" #include "mitkITKImageImport.h" #include "mitkPhotoacousticBeamformingFilter.h" #include #include -#include +#include "./OpenCLFilter/mitkPhotoacousticBModeFilter.h" // itk dependencies #include "itkImage.h" #include "itkResampleImageFilter.h" #include "itkCastImageFilter.h" #include "itkCropImageFilter.h" #include "itkRescaleIntensityImageFilter.h" #include "itkIntensityWindowingImageFilter.h" #include #include "itkMultiplyImageFilter.h" #include "itkBSplineInterpolateImageFunction.h" #include // needed itk image filters #include "mitkITKImageImport.h" #include "itkFFTShiftImageFilter.h" #include "itkMultiplyImageFilter.h" #include "itkComplexToModulusImageFilter.h" #include -#include "itkFFT1DComplexConjugateToRealImageFilter.h" -#include "itkFFT1DRealToComplexConjugateImageFilter.h" +#include "ITKFilter/ITKUltrasound/itkFFT1DComplexConjugateToRealImageFilter.h" +#include "ITKFilter/ITKUltrasound/itkFFT1DRealToComplexConjugateImageFilter.h" mitk::PhotoacousticImage::PhotoacousticImage() { MITK_INFO << "[PhotoacousticImage Debug] created that image"; } mitk::PhotoacousticImage::~PhotoacousticImage() { MITK_INFO << "[PhotoacousticImage Debug] destroyed that image"; } -mitk::Image::Pointer mitk::PhotoacousticImage::ApplyBmodeFilter(mitk::Image::Pointer inputImage, BModeMethod method, bool UseLogFilter, float resampleSpacing) +mitk::Image::Pointer mitk::PhotoacousticImage::ApplyBmodeFilter(mitk::Image::Pointer inputImage, BModeMethod method, bool UseGPU, bool UseLogFilter, float resampleSpacing) { // the image needs to be of floating point type for the envelope filter to work; the casting is done automatically by the CastToItkImage typedef itk::Image< float, 3 > itkFloatImageType; typedef itk::IdentityTransform TransformType; if (method == BModeMethod::Abs) { - auto input = ApplyCropping(inputImage, 0, 0, 0, 0, 0, inputImage->GetDimension(2) - 1); - PhotoacousticBModeFilter::Pointer filter = PhotoacousticBModeFilter::New(); - filter->SetParameters(UseLogFilter); - filter->SetInput(input); - filter->Update(); + mitk::Image::Pointer input; + mitk::Image::Pointer out; + if (inputImage->GetPixelType().GetTypeAsString() == "scalar (float)" || inputImage->GetPixelType().GetTypeAsString() == " (float)") + input = inputImage; + else + input = ApplyCropping(inputImage, 0, 0, 0, 0, 0, inputImage->GetDimension(2) - 1); + + if (!UseGPU) + { + PhotoacousticBModeFilter::Pointer filter = PhotoacousticBModeFilter::New(); + filter->SetParameters(UseLogFilter); + filter->SetInput(input); + filter->Update(); + + out = filter->GetOutput(); + + if (resampleSpacing == 0) + return out; + } + #ifdef PHOTOACOUSTICS_USE_GPU + else + { + PhotoacousticOCLBModeFilter::Pointer filter = PhotoacousticOCLBModeFilter::New(); + filter->SetParameters(UseLogFilter); + filter->SetInput(input); + filter->Update(); - auto out = filter->GetOutput(); + out = filter->GetOutput(); - if(resampleSpacing == 0) - return out; + if (resampleSpacing == 0) + return out; + } + #endif typedef itk::ResampleImageFilter < itkFloatImageType, itkFloatImageType > ResampleImageFilter; ResampleImageFilter::Pointer resampleImageFilter = ResampleImageFilter::New(); itkFloatImageType::Pointer itkImage; mitk::CastToItkImage(out, itkImage); itkFloatImageType::SpacingType outputSpacing; itkFloatImageType::SizeType inputSize = itkImage->GetLargestPossibleRegion().GetSize(); itkFloatImageType::SizeType outputSize = inputSize; outputSpacing[0] = itkImage->GetSpacing()[0]; outputSpacing[1] = resampleSpacing; outputSpacing[2] = itkImage->GetSpacing()[2]; outputSize[1] = inputSize[1] * itkImage->GetSpacing()[1] / outputSpacing[1]; typedef itk::IdentityTransform TransformType; resampleImageFilter->SetInput(itkImage); resampleImageFilter->SetSize(outputSize); resampleImageFilter->SetOutputSpacing(outputSpacing); resampleImageFilter->SetTransform(TransformType::New()); resampleImageFilter->UpdateLargestPossibleRegion(); return mitk::GrabItkImageMemory(resampleImageFilter->GetOutput()); } else if (method == BModeMethod::ShapeDetection) { typedef itk::BModeImageFilter < itkFloatImageType, itkFloatImageType > BModeFilterType; BModeFilterType::Pointer bModeFilter = BModeFilterType::New(); // LogFilter typedef itk::PhotoacousticBModeImageFilter < itkFloatImageType, itkFloatImageType > PhotoacousticBModeImageFilter; PhotoacousticBModeImageFilter::Pointer photoacousticBModeFilter = PhotoacousticBModeImageFilter::New(); // No LogFilter typedef itk::ResampleImageFilter < itkFloatImageType, itkFloatImageType > ResampleImageFilter; ResampleImageFilter::Pointer resampleImageFilter = ResampleImageFilter::New(); itkFloatImageType::Pointer itkImage; mitk::CastToItkImage(inputImage, itkImage); itkFloatImageType::Pointer bmode; if (UseLogFilter) { bModeFilter->SetInput(itkImage); bModeFilter->SetDirection(1); bmode = bModeFilter->GetOutput(); } else { photoacousticBModeFilter->SetInput(itkImage); photoacousticBModeFilter->SetDirection(1); bmode = photoacousticBModeFilter->GetOutput(); } // resampleSpacing == 0 means: do no resampling if (resampleSpacing == 0) { return mitk::GrabItkImageMemory(bmode); } itkFloatImageType::SpacingType outputSpacing; itkFloatImageType::SizeType inputSize = itkImage->GetLargestPossibleRegion().GetSize(); itkFloatImageType::SizeType outputSize = inputSize; outputSpacing[0] = itkImage->GetSpacing()[0]; outputSpacing[1] = resampleSpacing; outputSpacing[2] = itkImage->GetSpacing()[2]; outputSize[1] = inputSize[1] * itkImage->GetSpacing()[1] / outputSpacing[1]; resampleImageFilter->SetInput(bmode); resampleImageFilter->SetSize(outputSize); resampleImageFilter->SetOutputSpacing(outputSpacing); resampleImageFilter->SetTransform(TransformType::New()); resampleImageFilter->UpdateLargestPossibleRegion(); return mitk::GrabItkImageMemory(resampleImageFilter->GetOutput()); } return nullptr; } /*mitk::Image::Pointer mitk::PhotoacousticImage::ApplyScatteringCompensation(mitk::Image::Pointer inputImage, int scattering) { typedef itk::Image< float, 3 > itkFloatImageType; typedef itk::MultiplyImageFilter MultiplyImageFilterType; itkFloatImageType::Pointer itkImage; mitk::CastToItkImage(inputImage, itkImage); MultiplyImageFilterType::Pointer multiplyFilter = MultiplyImageFilterType::New(); multiplyFilter->SetInput1(itkImage); multiplyFilter->SetInput2(m_FluenceCompResizedItk.at(m_ScatteringCoefficient)); return mitk::GrabItkImageMemory(multiplyFilter->GetOutput()); }*/ mitk::Image::Pointer mitk::PhotoacousticImage::ApplyResampling(mitk::Image::Pointer inputImage, unsigned int outputSize[2]) { typedef itk::Image< float, 3 > itkFloatImageType; typedef itk::ResampleImageFilter < itkFloatImageType, itkFloatImageType > ResampleImageFilter; ResampleImageFilter::Pointer resampleImageFilter = ResampleImageFilter::New(); typedef itk::LinearInterpolateImageFunction T_Interpolator; itkFloatImageType::Pointer itkImage; mitk::CastToItkImage(inputImage, itkImage); itkFloatImageType::SpacingType outputSpacingItk; itkFloatImageType::SizeType inputSizeItk = itkImage->GetLargestPossibleRegion().GetSize(); itkFloatImageType::SizeType outputSizeItk = inputSizeItk; outputSizeItk[0] = outputSize[0]; outputSizeItk[1] = outputSize[1]; outputSizeItk[2] = inputSizeItk[2]; outputSpacingItk[0] = itkImage->GetSpacing()[0] * (static_cast(inputSizeItk[0]) / static_cast(outputSizeItk[0])); outputSpacingItk[1] = itkImage->GetSpacing()[1] * (static_cast(inputSizeItk[1]) / static_cast(outputSizeItk[1])); outputSpacingItk[2] = itkImage->GetSpacing()[2]; typedef itk::IdentityTransform TransformType; T_Interpolator::Pointer _pInterpolator = T_Interpolator::New(); resampleImageFilter->SetInput(itkImage); resampleImageFilter->SetSize(outputSizeItk); resampleImageFilter->SetOutputSpacing(outputSpacingItk); resampleImageFilter->SetTransform(TransformType::New()); resampleImageFilter->SetInterpolator(_pInterpolator); resampleImageFilter->UpdateLargestPossibleRegion(); return mitk::GrabItkImageMemory(resampleImageFilter->GetOutput()); } mitk::Image::Pointer mitk::PhotoacousticImage::ApplyCropping(mitk::Image::Pointer inputImage, int above, int below, int right, int left, int minSlice, int maxSlice) { unsigned int inputDim[3] = { inputImage->GetDimension(0), inputImage->GetDimension(1), inputImage->GetDimension(2) }; unsigned int outputDim[3] = { inputImage->GetDimension(0) - left - right, inputImage->GetDimension(1) - (unsigned int)above - (unsigned int)below, (unsigned int)maxSlice - (unsigned int)minSlice + 1 }; void* inputData; float* outputData = new float[outputDim[0] * outputDim[1] * outputDim[2]]; ImageReadAccessor acc(inputImage); inputData = const_cast(acc.GetData()); // convert the data to float by default // as of now only those float, short, float are used at all... though it's easy to add other ones if (inputImage->GetPixelType().GetTypeAsString() == "scalar (float)" || inputImage->GetPixelType().GetTypeAsString() == " (float)") { // copy the data into the cropped image for (unsigned short sl = 0; sl < outputDim[2]; ++sl) { for (unsigned short l = 0; l < outputDim[0]; ++l) { for (unsigned short s = 0; s < outputDim[1]; ++s) { outputData[l + s*(unsigned short)outputDim[0] + sl*outputDim[0] * outputDim[1]] = (float)((float*)inputData)[(l + left) + (s + above)*(unsigned short)inputDim[0] + (sl + minSlice)*inputDim[0] * inputDim[1]]; } } } } else if (inputImage->GetPixelType().GetTypeAsString() == "scalar (short)" || inputImage->GetPixelType().GetTypeAsString() == " (short)") { // copy the data unsigned shorto the cropped image for (unsigned short sl = 0; sl < outputDim[2]; ++sl) { for (unsigned short l = 0; l < outputDim[0]; ++l) { for (unsigned short s = 0; s < outputDim[1]; ++s) { outputData[l + s*(unsigned short)outputDim[0] + sl*outputDim[0] * outputDim[1]] = (float)((short*)inputData)[(l + left) + (s + above)*(unsigned short)inputDim[0] + (sl + minSlice)*inputDim[0] * inputDim[1]]; } } } } else if (inputImage->GetPixelType().GetTypeAsString() == "scalar (double)" || inputImage->GetPixelType().GetTypeAsString() == " (double)") { // copy the data unsigned shorto the cropped image for (unsigned short sl = 0; sl < outputDim[2]; ++sl) { for (unsigned short l = 0; l < outputDim[0]; ++l) { for (unsigned short s = 0; s < outputDim[1]; ++s) { outputData[l + s*(unsigned short)outputDim[0] + sl*outputDim[0] * outputDim[1]] = (float)((double*)inputData)[(l + left) + (s + above)*(unsigned short)inputDim[0] + (sl + minSlice)*inputDim[0] * inputDim[1]]; } } } } else { MITK_INFO << "Could not determine pixel type"; } mitk::Image::Pointer output = mitk::Image::New(); output->Initialize(mitk::MakeScalarPixelType(), 3, outputDim); output->SetSpacing(inputImage->GetGeometry()->GetSpacing()); output->SetImportVolume(outputData, 0, 0, mitk::Image::ReferenceMemory); return output; } -mitk::Image::Pointer mitk::PhotoacousticImage::ApplyBeamforming(mitk::Image::Pointer inputImage, BeamformingFilter::beamformingSettings config, int cutoff, std::function progressHandle) +mitk::Image::Pointer mitk::PhotoacousticImage::ApplyBeamforming(mitk::Image::Pointer inputImage, BeamformingSettings config, int cutoff, std::function progressHandle) { - // crop the image - // set the Maximum Size of the image to 4096 - unsigned short lowerCutoff = 0; - if (((unsigned int)(4096 + cutoff)) < inputImage->GetDimension(1)) - { - lowerCutoff = (unsigned short)(inputImage->GetDimension(1) - 4096); - } - - config.RecordTime = config.RecordTime - (cutoff + lowerCutoff) / inputImage->GetDimension(1) * config.RecordTime; // adjust the recorded time lost by cropping + config.RecordTime = config.RecordTime - (cutoff) / inputImage->GetDimension(1) * config.RecordTime; // adjust the recorded time lost by cropping progressHandle(0, "cropping image"); if (!config.partial) { config.CropBounds[0] = 0; config.CropBounds[1] = inputImage->GetDimension(2) - 1; } - Image::Pointer processedImage = ApplyCropping(inputImage, cutoff, lowerCutoff, 0, 0, config.CropBounds[0], config.CropBounds[1]); - - // resample the image in horizontal direction - if (inputImage->GetDimension(0) != config.ReconstructionLines) - { - progressHandle(0, "resampling image"); - auto begin = std::chrono::high_resolution_clock::now(); - unsigned int dim[2] = { config.ReconstructionLines, processedImage->GetDimension(1) }; - processedImage = ApplyResampling(processedImage, dim); - auto end = std::chrono::high_resolution_clock::now(); - MITK_DEBUG << "Upsampling from " << inputImage->GetDimension(0) << " to " << config.ReconstructionLines << " lines completed in " << ((double)std::chrono::duration_cast(end - begin).count()) / 1000000 << "ms" << std::endl; - } + Image::Pointer processedImage = ApplyCropping(inputImage, cutoff, 0, 0, 0, config.CropBounds[0], config.CropBounds[1]); + config.inputDim[0] = processedImage->GetDimension(0); + config.inputDim[1] = processedImage->GetDimension(1); + config.inputDim[2] = processedImage->GetDimension(2); // perform the beamforming BeamformingFilter::Pointer Beamformer = BeamformingFilter::New(); Beamformer->SetInput(processedImage); Beamformer->Configure(config); Beamformer->SetProgressHandle(progressHandle); Beamformer->UpdateLargestPossibleRegion(); processedImage = Beamformer->GetOutput(); return processedImage; } mitk::Image::Pointer mitk::PhotoacousticImage::BandpassFilter(mitk::Image::Pointer data, float recordTime, float BPHighPass, float BPLowPass, float alpha) { bool powerOfTwo = false; int finalPower = 0; for (int i = 1; pow(2, i) <= data->GetDimension(1); ++i) { finalPower = i; if (pow(2, i) == data->GetDimension(1)) { powerOfTwo = true; } } if (!powerOfTwo) { unsigned int dim[2] = { data->GetDimension(0), (unsigned int)pow(2,finalPower+1)}; data = ApplyResampling(data, dim); } MITK_INFO << data->GetDimension(0); // do a fourier transform, multiply with an appropriate window for the filter, and transform back typedef float PixelType; typedef itk::Image< PixelType, 3 > RealImageType; RealImageType::Pointer image; mitk::CastToItkImage(data, image); typedef itk::FFT1DRealToComplexConjugateImageFilter ForwardFFTFilterType; typedef ForwardFFTFilterType::OutputImageType ComplexImageType; ForwardFFTFilterType::Pointer forwardFFTFilter = ForwardFFTFilterType::New(); forwardFFTFilter->SetInput(image); forwardFFTFilter->SetDirection(1); try { forwardFFTFilter->UpdateOutputInformation(); } catch (itk::ExceptionObject & error) { std::cerr << "Error: " << error << std::endl; MITK_WARN << "Bandpass could not be applied"; return data; } float singleVoxel = 1 / (recordTime / data->GetDimension(1)) / 2 / 1000; float cutoffPixelHighPass = std::min(BPHighPass / singleVoxel, (float)data->GetDimension(1) / 2); float cutoffPixelLowPass = std::min(BPLowPass / singleVoxel, (float)data->GetDimension(1) / 2 - cutoffPixelHighPass); RealImageType::Pointer fftMultiplicator = BPFunction(data, cutoffPixelHighPass, cutoffPixelLowPass, alpha); typedef itk::MultiplyImageFilter< ComplexImageType, RealImageType, ComplexImageType > MultiplyFilterType; MultiplyFilterType::Pointer multiplyFilter = MultiplyFilterType::New(); multiplyFilter->SetInput1(forwardFFTFilter->GetOutput()); multiplyFilter->SetInput2(fftMultiplicator); /*itk::ComplexToModulusImageFilter::Pointer toReal = itk::ComplexToModulusImageFilter::New(); toReal->SetInput(forwardFFTFilter->GetOutput()); return GrabItkImageMemory(toReal->GetOutput()); return GrabItkImageMemory(fftMultiplicator); *///DEBUG typedef itk::FFT1DComplexConjugateToRealImageFilter< ComplexImageType, RealImageType > InverseFilterType; InverseFilterType::Pointer inverseFFTFilter = InverseFilterType::New(); inverseFFTFilter->SetInput(multiplyFilter->GetOutput()); inverseFFTFilter->SetDirection(1); return GrabItkImageMemory(inverseFFTFilter->GetOutput()); } itk::Image::Pointer mitk::PhotoacousticImage::BPFunction(mitk::Image::Pointer reference, int cutoffFrequencyPixelHighPass, int cutoffFrequencyPixelLowPass, float alpha) { float* imageData = new float[reference->GetDimension(0)*reference->GetDimension(1)]; // tukey window float width = reference->GetDimension(1) / 2 - (float)cutoffFrequencyPixelHighPass - (float)cutoffFrequencyPixelLowPass; float center = (float)cutoffFrequencyPixelHighPass / 2 + width / 2; MITK_INFO << width << "width " << center << "center " << alpha; for (unsigned int n = 0; n < reference->GetDimension(1); ++n) { imageData[reference->GetDimension(0)*n] = 0; } for (int n = 0; n < width; ++n) { if (n <= (alpha*(width - 1)) / 2) { imageData[reference->GetDimension(0)*(int)(n + center - (width / 2))] = (1 + cos(M_PI*(2 * n / (alpha*(width - 1)) - 1))) / 2; } else if (n >= (width - 1)*(1 - alpha / 2) && n <= (width - 1)) { imageData[reference->GetDimension(0)*(int)(n + center - (width / 2))] = (1 + cos(M_PI*(2 * n / (alpha*(width - 1)) + 1 - 2 / alpha))) / 2; } else { imageData[reference->GetDimension(0)*(int)(n + center - (width / 2))] = 1; } } // Butterworth-Filter /* // first, write the HighPass if (cutoffFrequencyPixelHighPass != reference->GetDimension(1) / 2) { for (int n = 0; n < reference->GetDimension(1) / 2; ++n) { imageData[reference->GetDimension(0)*n] = 1 / (1 + pow( (float)n / (float)(reference->GetDimension(1) / 2 - cutoffFrequencyPixelHighPass) , 2 * butterworthOrder)); } } else { for (int n = 0; n < reference->GetDimension(1) / 2; ++n) { imageData[reference->GetDimension(0)*n] = 1; } } // now, the LowPass for (int n = 0; n < reference->GetDimension(1) / 2; ++n) { imageData[reference->GetDimension(0)*n] *= 1 / (1 + pow( (float)(reference->GetDimension(1) / 2 - 1 - n) / (float)(reference->GetDimension(1) / 2 - cutoffFrequencyPixelLowPass) , 2 * butterworthOrder)); } */ // mirror the first half of the image for (unsigned int n = reference->GetDimension(1) / 2; n < reference->GetDimension(1); ++n) { imageData[reference->GetDimension(0)*n] = imageData[(reference->GetDimension(1) - (n + 1)) * reference->GetDimension(0)]; } // copy and paste to all lines for (unsigned int line = 1; line < reference->GetDimension(0); ++line) { for (unsigned int sample = 0; sample < reference->GetDimension(1); ++sample) { imageData[reference->GetDimension(0)*sample + line] = imageData[reference->GetDimension(0)*sample]; } } typedef itk::Image< float, 3U > ImageType; ImageType::RegionType region; ImageType::IndexType start; start.Fill(0); region.SetIndex(start); ImageType::SizeType size; size[0] = reference->GetDimension(0); size[1] = reference->GetDimension(1); size[2] = reference->GetDimension(2); region.SetSize(size); ImageType::SpacingType SpacingItk; SpacingItk[0] = reference->GetGeometry()->GetSpacing()[0]; SpacingItk[1] = reference->GetGeometry()->GetSpacing()[1]; SpacingItk[2] = reference->GetGeometry()->GetSpacing()[2]; ImageType::Pointer image = ImageType::New(); image->SetRegions(region); image->Allocate(); image->FillBuffer(itk::NumericTraits::Zero); image->SetSpacing(SpacingItk); ImageType::IndexType pixelIndex; for (ImageType::IndexValueType slice = 0; slice < reference->GetDimension(2); ++slice) { for (ImageType::IndexValueType line = 0; line < reference->GetDimension(0); ++line) { for (ImageType::IndexValueType sample = 0; sample < reference->GetDimension(1); ++sample) { pixelIndex[0] = line; pixelIndex[1] = sample; pixelIndex[2] = slice; image->SetPixel(pixelIndex, imageData[line + sample*reference->GetDimension(0)]); } } } delete[] imageData; return image; -} - - -/* -mitk::CropFilter::CropFilter() - : m_PixelCalculation(NULL) -{ - this->AddSourceFile("CropFilter.cl"); - - this->m_FilterID = "CropFilter"; -} - -mitk::CropFilter::~CropFilter() -{ - if (this->m_PixelCalculation) - { - clReleaseKernel(m_PixelCalculation); - } -} - -void mitk::CropFilter::Update() -{ - //Check if context & program available - if (!this->Initialize()) - { - us::ServiceReference ref = GetModuleContext()->GetServiceReference(); - OclResourceService* resources = GetModuleContext()->GetService(ref); - - // clean-up also the resources - resources->InvalidateStorage(); - mitkThrow() << "Filter is not initialized. Cannot update."; - } - else { - // Execute - this->Execute(); - } -} - -void mitk::CropFilter::Execute() -{ - cl_int clErr = 0; - - try - { - this->InitExec(this->m_PixelCalculation); - } - catch (const mitk::Exception& e) - { - MITK_ERROR << "Catched exception while initializing filter: " << e.what(); - return; - } - - us::ServiceReference ref = GetModuleContext()->GetServiceReference(); - OclResourceService* resources = GetModuleContext()->GetService(ref); - cl_context gpuContext = resources->GetContext(); - - unsigned int size = m_OutputDim[0] * m_OutputDim[1] * m_OutputDim[2] * m_Images; - - cl_mem cl_input = clCreateBuffer(gpuContext, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, sizeof(float) * size, m_Data, &clErr); - CHECK_OCL_ERR(clErr); - - // set kernel arguments - clErr = clSetKernelArg(this->m_PixelCalculation, 2, sizeof(cl_mem), &cl_input); - clErr |= clSetKernelArg(this->m_PixelCalculation, 3, sizeof(cl_ushort), &(this->m_Images)); - - CHECK_OCL_ERR(clErr); - - // execute the filter on a 3D NDRange - this->ExecuteKernel(m_PixelCalculation, 3); - - // signalize the GPU-side data changed - m_Output->Modified(GPU_DATA); -} - -us::Module *mitk::CropFilter::GetModule() -{ - return us::GetModuleContext()->GetModule(); -} - -bool mitk::CropFilter::Initialize() -{ - bool buildErr = true; - cl_int clErr = 0; - - if (OclFilter::Initialize()) - { - this->m_PixelCalculation = clCreateKernel(this->m_ClProgram, "ckCrop", &clErr); - buildErr |= CHECK_OCL_ERR(clErr); - } - return (OclFilter::IsInitialized() && buildErr); -} - -void mitk::CropFilter::SetInput(mitk::Image::Pointer image) -{ - if (image->GetDimension() != 3) - { - mitkThrowException(mitk::Exception) << "Input for " << this->GetNameOfClass() << - " is not 3D. The filter only supports 3D. Please change your input."; - } - OclImageToImageFilter::SetInput(image); -} - -mitk::Image::Pointer mitk::CropFilter::GetOutput() -{ - if (m_Output->IsModified(GPU_DATA)) - { - void* pData = m_Output->TransferDataToCPU(m_CommandQue); - - const unsigned int dimension = 3; - unsigned int* dimensions = m_OutputDim; - - const mitk::SlicedGeometry3D::Pointer p_slg = m_Input->GetMITKImage()->GetSlicedGeometry(); - - MITK_DEBUG << "Creating new MITK Image."; - - m_Output->GetMITKImage()->Initialize(this->GetOutputType(), dimension, dimensions); - m_Output->GetMITKImage()->SetSpacing(p_slg->GetSpacing()); - m_Output->GetMITKImage()->SetGeometry(m_Input->GetMITKImage()->GetGeometry()); - m_Output->GetMITKImage()->SetImportVolume(pData, 0, 0, mitk::Image::ReferenceMemory); - } - - MITK_DEBUG << "Image Initialized."; - - return m_Output->GetMITKImage(); -} - -*/ +} \ No newline at end of file diff --git a/Modules/PhotoacousticsAlgorithms/mitkPhotoacousticImage.h b/Modules/PhotoacousticsAlgorithms/mitkPhotoacousticImage.h index daab4a43cf..2200124e8d 100644 --- a/Modules/PhotoacousticsAlgorithms/mitkPhotoacousticImage.h +++ b/Modules/PhotoacousticsAlgorithms/mitkPhotoacousticImage.h @@ -1,53 +1,50 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ - #ifndef mitkPhotoacousticImage_H_HEADER_INCLUDED #define mitkPhotoacousticImage_H_HEADER_INCLUDED #include "itkObject.h" #include "mitkCommon.h" #include "mitkImage.h" #include -#include "mitkOclImageToImageFilter.h" #include "mitkPhotoacousticBeamformingFilter.h" - #include "MitkPhotoacousticsAlgorithmsExports.h" namespace mitk { class MITKPHOTOACOUSTICSALGORITHMS_EXPORT PhotoacousticImage : public itk::Object { public: mitkClassMacroItkParent(mitk::PhotoacousticImage, itk::Object); itkFactorylessNewMacro(Self); enum BModeMethod { ShapeDetection, Abs }; - mitk::Image::Pointer ApplyBmodeFilter(mitk::Image::Pointer inputImage, BModeMethod method = BModeMethod::Abs, bool UseLogFilter = false, float resampleSpacing = 0.15); + mitk::Image::Pointer ApplyBmodeFilter(mitk::Image::Pointer inputImage, BModeMethod method = BModeMethod::Abs, bool UseGPU = false, bool UseLogFilter = false, float resampleSpacing = 0.15); // mitk::Image::Pointer ApplyScatteringCompensation(mitk::Image::Pointer inputImage, int scatteringCoefficient); mitk::Image::Pointer ApplyResampling(mitk::Image::Pointer inputImage, unsigned int outputSize[2]); - mitk::Image::Pointer ApplyBeamforming(mitk::Image::Pointer inputImage, BeamformingFilter::beamformingSettings config, int cutoff, std::function progressHandle = [](int, std::string) {}); + mitk::Image::Pointer ApplyBeamforming(mitk::Image::Pointer inputImage, BeamformingSettings config, int cutoff, std::function progressHandle = [](int, std::string) {}); mitk::Image::Pointer ApplyCropping(mitk::Image::Pointer inputImage, int above, int below, int right, int left, int minSlice, int maxSlice); mitk::Image::Pointer BandpassFilter(mitk::Image::Pointer data, float recordTime, float BPHighPass, float BPLowPass, float alpha); protected: PhotoacousticImage(); virtual ~PhotoacousticImage(); itk::Image::Pointer BPFunction(mitk::Image::Pointer reference, int cutoffFrequencyPixelHighPass, int cutoffFrequencyPixelLowPass, float alpha); }; } // namespace mitk #endif /* mitkPhotoacousticImage_H_HEADER_INCLUDED */ diff --git a/Modules/PhotoacousticsAlgorithms/source/OpenCLFilter/mitkPhotoacousticBModeFilter.cpp b/Modules/PhotoacousticsAlgorithms/source/OpenCLFilter/mitkPhotoacousticBModeFilter.cpp new file mode 100644 index 0000000000..f9db6a7105 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/source/OpenCLFilter/mitkPhotoacousticBModeFilter.cpp @@ -0,0 +1,221 @@ +/*=================================================================== + +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 "./OpenCLFilter/mitkPhotoacousticBModeFilter.h" +#include "usServiceReference.h" +#include + +#if defined(PHOTOACOUSTICS_USE_GPU) || DOXYGEN + +mitk::PhotoacousticOCLBModeFilter::PhotoacousticOCLBModeFilter() + : m_PixelCalculation(NULL) +{ + this->AddSourceFile("BModeAbs.cl"); + this->AddSourceFile("BModeAbsLog.cl"); + + this->m_FilterID = "BModeFilter"; + + this->Initialize(); +} + +mitk::PhotoacousticOCLBModeFilter::~PhotoacousticOCLBModeFilter() +{ + if (this->m_PixelCalculation) + { + clReleaseKernel(m_PixelCalculation); + } +} + +void mitk::PhotoacousticOCLBModeFilter::Update() +{ + //Check if context & program available + if (!this->Initialize()) + { + us::ServiceReference ref = GetModuleContext()->GetServiceReference(); + OclResourceService* resources = GetModuleContext()->GetService(ref); + + // clean-up also the resources + resources->InvalidateStorage(); + mitkThrow() << "Filter is not initialized. Cannot update."; + } + else { + // Execute + this->Execute(); + } +} + +void mitk::PhotoacousticOCLBModeFilter::Execute() +{ + try + { + size_t outputSize = m_InputDim[0] * m_InputDim[1] * m_InputDim[2]; + this->InitExec(this->m_PixelCalculation, m_InputDim, outputSize, sizeof(float)); + } + catch (const mitk::Exception& e) + { + MITK_ERROR << "Catched exception while initializing filter: " << e.what(); + return; + } + + cl_int clErr; + clErr = clSetKernelArg(this->m_PixelCalculation, 2, sizeof(cl_uint), &(this->m_Size)); + + CHECK_OCL_ERR(clErr); + + // execute the filter on a 3D NDRange + this->ExecuteKernel(m_PixelCalculation, 3); + + // signalize the GPU-side data changed + m_Output->Modified(GPU_DATA); +} + +us::Module *mitk::PhotoacousticOCLBModeFilter::GetModule() +{ + return us::GetModuleContext()->GetModule(); +} + +bool mitk::PhotoacousticOCLBModeFilter::Initialize() +{ + bool buildErr = true; + cl_int clErr = 0; + + if (OclFilter::Initialize()) + { + if(m_UseLogFilter) + this->m_PixelCalculation = clCreateKernel(this->m_ClProgram, "ckBmodeAbsLog", &clErr); + else + this->m_PixelCalculation = clCreateKernel(this->m_ClProgram, "ckBmodeAbs", &clErr); + buildErr |= CHECK_OCL_ERR(clErr); + } + return (OclFilter::IsInitialized() && buildErr); +} + +void mitk::PhotoacousticOCLBModeFilter::SetInput(mitk::Image::Pointer image) +{ + OclDataSetToDataSetFilter::SetInput(image); + + m_InputImage = image; + m_InputDim[0] = m_InputImage->GetDimension(0); + m_InputDim[1] = m_InputImage->GetDimension(1); + m_InputDim[2] = m_InputImage->GetDimension(2); + m_Size = m_InputDim[0] * m_InputDim[1] * m_InputDim[2]; +} + +mitk::Image::Pointer mitk::PhotoacousticOCLBModeFilter::GetOutput() +{ + mitk::Image::Pointer outputImage = mitk::Image::New(); + + if (m_Output->IsModified(GPU_DATA)) + { + void* pData = m_Output->TransferDataToCPU(m_CommandQue); + + const unsigned int dimension = 3; + unsigned int dimensions[3] = { m_InputDim[0], m_InputDim[1], m_InputDim[2] }; + + const mitk::SlicedGeometry3D::Pointer p_slg = m_InputImage->GetSlicedGeometry(); + + MITK_DEBUG << "Creating new MITK Image."; + + outputImage->Initialize(this->GetOutputType(), dimension, dimensions); + outputImage->SetSpacing(p_slg->GetSpacing()); + outputImage->SetGeometry(m_InputImage->GetGeometry()); + outputImage->SetImportVolume(pData, 0, 0, mitk::Image::ReferenceMemory); + } + + MITK_DEBUG << "Image Initialized."; + + return outputImage; +} + +#endif + + +mitk::PhotoacousticBModeFilter::PhotoacousticBModeFilter() : m_UseLogFilter(false) +{ + this->SetNumberOfIndexedInputs(1); + this->SetNumberOfRequiredInputs(1); +} + +mitk::PhotoacousticBModeFilter::~PhotoacousticBModeFilter() +{ +} + +void mitk::PhotoacousticBModeFilter::GenerateInputRequestedRegion() +{ + Superclass::GenerateInputRequestedRegion(); + + mitk::Image* output = this->GetOutput(); + mitk::Image* input = const_cast (this->GetInput()); + if (!output->IsInitialized()) + { + return; + } + + input->SetRequestedRegionToLargestPossibleRegion(); + + //GenerateTimeInInputRegion(output, input); +} + +void mitk::PhotoacousticBModeFilter::GenerateOutputInformation() +{ + mitk::Image::ConstPointer input = this->GetInput(); + mitk::Image::Pointer output = this->GetOutput(); + + if ((output->IsInitialized()) && (this->GetMTime() <= m_TimeOfHeaderInitialization.GetMTime())) + return; + + itkDebugMacro(<< "GenerateOutputInformation()"); + + output->Initialize(input); + output->GetGeometry()->SetSpacing(input->GetGeometry()->GetSpacing()); + output->GetGeometry()->Modified(); + output->SetPropertyList(input->GetPropertyList()->Clone()); + + m_TimeOfHeaderInitialization.Modified(); +} + +void mitk::PhotoacousticBModeFilter::GenerateData() +{ + GenerateOutputInformation(); + mitk::Image::Pointer input = this->GetInput(); + mitk::Image::Pointer output = this->GetOutput(); + + if (!output->IsInitialized()) + return; + + mitk::ImageReadAccessor reader(input); + + unsigned int size = output->GetDimension(0) * output->GetDimension(1) * output->GetDimension(2); + + float* InputData = (float*)const_cast(reader.GetData()); + float* OutputData = new float[size]; + if(!m_UseLogFilter) + for (unsigned int i = 0; i < size; ++i) + { + OutputData[i] = abs(InputData[i]); + } + else + { + for (unsigned int i = 0; i < size; ++i) + { + OutputData[i] = log(abs(InputData[i])); + } + } + + output->SetImportVolume(OutputData, 0, 0, mitk::Image::ImportMemoryManagementType::ManageMemory); + + m_TimeOfHeaderInitialization.Modified(); +} \ No newline at end of file diff --git a/Modules/PhotoacousticsAlgorithms/source/OpenCLFilter/mitkPhotoacousticOCLBeamformingFilter.cpp b/Modules/PhotoacousticsAlgorithms/source/OpenCLFilter/mitkPhotoacousticOCLBeamformingFilter.cpp new file mode 100644 index 0000000000..575c29b240 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/source/OpenCLFilter/mitkPhotoacousticOCLBeamformingFilter.cpp @@ -0,0 +1,264 @@ +/*=================================================================== + +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(PHOTOACOUSTICS_USE_GPU) || DOXYGEN + +#include "./OpenCLFilter/mitkPhotoacousticOCLBeamformingFilter.h" +#include "usServiceReference.h" + +mitk::PhotoacousticOCLBeamformingFilter::PhotoacousticOCLBeamformingFilter() +: m_PixelCalculation( NULL ), m_InputImage(mitk::Image::New()), m_ApodizationBuffer(nullptr), m_MemoryLocationsBuffer(nullptr), m_DelaysBuffer(nullptr), m_UsedLinesBuffer(nullptr) +{ + this->AddSourceFile("DAS.cl"); + this->AddSourceFile("DMAS.cl"); + this->AddSourceFile("sDMAS.cl"); + this->m_FilterID = "OpenCLBeamformingFilter"; + + this->Initialize(); + + unsigned int dim[] = { 128, 2048, 2 }; + + mitk::Vector3D spacing; + spacing[0] = 1; + spacing[1] = 1; + spacing[2] = 1; + + m_InputImage->Initialize(mitk::MakeScalarPixelType(), 3, dim); + m_InputImage->SetSpacing(spacing); + + m_ChunkSize[0] = 128; + m_ChunkSize[1] = 128; + m_ChunkSize[2] = 8; + + m_UsedLinesCalculation = mitk::OCLUsedLinesCalculation::New(); + m_DelayCalculation = mitk::OCLDelayCalculation::New(); +} + +mitk::PhotoacousticOCLBeamformingFilter::~PhotoacousticOCLBeamformingFilter() +{ + if ( this->m_PixelCalculation ) + { + clReleaseKernel( m_PixelCalculation ); + } + + if (m_ApodizationBuffer) clReleaseMemObject(m_ApodizationBuffer); +} + +void mitk::PhotoacousticOCLBeamformingFilter::Update() +{ + //Check if context & program available + if (!this->Initialize()) + { + us::ServiceReference ref = GetModuleContext()->GetServiceReference(); + OclResourceService* resources = GetModuleContext()->GetService(ref); + + // clean-up also the resources + resources->InvalidateStorage(); + mitkThrow() <<"Filter is not initialized. Cannot update."; + } + else{ + // Execute + this->Execute(); + } +} + +void mitk::PhotoacousticOCLBeamformingFilter::UpdateDataBuffers() +{ + /*us::ServiceReference ref = GetModuleContext()->GetServiceReference(); + OclResourceService* resources = GetModuleContext()->GetService(ref); + cl_ulong globalMemSize = oclGetGlobalMemSize(resources->GetCurrentDevice());*/ + //Initialize the Output + + try + { + MITK_DEBUG << "Updating Workgroup size for new dimensions"; + size_t outputSize = (size_t)m_Conf.ReconstructionLines * (size_t)m_Conf.SamplesPerLine * (size_t)m_Conf.inputDim[2]; + m_OutputDim[0] = m_Conf.ReconstructionLines; + m_OutputDim[1] = m_Conf.SamplesPerLine; + m_OutputDim[2] = m_Conf.inputDim[2]; + this->InitExec(this->m_PixelCalculation, m_OutputDim, outputSize, sizeof(float)); + } + catch (const mitk::Exception& e) + { + MITK_ERROR << "Caught exception while initializing filter: " << e.what(); + return; + } + + if (BeamformingSettings::SettingsChangedOpenCL(m_Conf, m_ConfOld)) + { + cl_int clErr = 0; + MITK_DEBUG << "Updating GPU Buffers for new configuration"; + + // create the apodisation buffer + + if (m_Apodisation == nullptr) + { + MITK_INFO << "No apodisation function set; Beamforming will be done without any apodisation."; + m_Apodisation = new float[1]; + m_Apodisation[0] = 1; + m_ApodArraySize = 1; + } + + us::ServiceReference ref = GetModuleContext()->GetServiceReference(); + OclResourceService* resources = GetModuleContext()->GetService(ref); + cl_context gpuContext = resources->GetContext(); + + if (m_ApodizationBuffer) clReleaseMemObject(m_ApodizationBuffer); + + this->m_ApodizationBuffer = clCreateBuffer(gpuContext, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, sizeof(float) * m_ApodArraySize, m_Apodisation, &clErr); + CHECK_OCL_ERR(clErr); + + // calculate used lines + + m_UsedLinesCalculation->SetConfig(m_Conf); + m_UsedLinesCalculation->Update(); + m_UsedLinesBuffer = m_UsedLinesCalculation->GetGPUOutput()->GetGPUBuffer(); + + // calculate the Delays + m_DelayCalculation->SetConfig(m_Conf); + m_DelayCalculation->SetInputs(m_UsedLinesBuffer); + m_DelayCalculation->Update(); + + m_DelaysBuffer = m_DelayCalculation->GetGPUOutput()->GetGPUBuffer(); + + m_ConfOld = m_Conf; + } +} + +void mitk::PhotoacousticOCLBeamformingFilter::Execute() +{ + cl_int clErr = 0; + UpdateDataBuffers(); + + clErr = clSetKernelArg(this->m_PixelCalculation, 2, sizeof(cl_mem), &(this->m_UsedLinesBuffer)); + clErr |= clSetKernelArg(this->m_PixelCalculation, 3, sizeof(cl_mem), &(this->m_DelaysBuffer)); + clErr |= clSetKernelArg(this->m_PixelCalculation, 4, sizeof(cl_mem), &(this->m_ApodizationBuffer)); + clErr |= clSetKernelArg(this->m_PixelCalculation, 5, sizeof(cl_ushort), &(this->m_ApodArraySize)); + clErr |= clSetKernelArg(this->m_PixelCalculation, 6, sizeof(cl_uint), &(this->m_Conf.inputDim[0])); + clErr |= clSetKernelArg(this->m_PixelCalculation, 7, sizeof(cl_uint), &(this->m_Conf.inputDim[1])); + clErr |= clSetKernelArg(this->m_PixelCalculation, 8, sizeof(cl_uint), &(this->m_Conf.inputDim[2])); + clErr |= clSetKernelArg(this->m_PixelCalculation, 9, sizeof(cl_uint), &(this->m_Conf.ReconstructionLines)); + clErr |= clSetKernelArg(this->m_PixelCalculation, 10, sizeof(cl_uint), &(this->m_Conf.SamplesPerLine)); + + // execute the filter on a 3D NDRange + if (m_OutputDim[2] == 1 || m_ChunkSize[2] == 1) + { + if(!this->ExecuteKernelChunksInBatches(m_PixelCalculation, 2, m_ChunkSize, 16, 50)) + mitkThrow() << "openCL Error when executing Kernel"; + } + else + { + if(!this->ExecuteKernelChunksInBatches(m_PixelCalculation, 3, m_ChunkSize, 16, 50)) + mitkThrow() << "openCL Error when executing Kernel"; + } + + // signalize the GPU-side data changed + m_Output->Modified( GPU_DATA ); +} + +us::Module *mitk::PhotoacousticOCLBeamformingFilter::GetModule() +{ + return us::GetModuleContext()->GetModule(); +} + +bool mitk::PhotoacousticOCLBeamformingFilter::Initialize() +{ + bool buildErr = true; + cl_int clErr = 0; + + if ( OclFilter::Initialize() ) + { + switch (m_Conf.Algorithm) + { + case BeamformingSettings::BeamformingAlgorithm::DAS: + { + this->m_PixelCalculation = clCreateKernel(this->m_ClProgram, "ckDAS", &clErr); + break; + } + case BeamformingSettings::BeamformingAlgorithm::DMAS: + { + this->m_PixelCalculation = clCreateKernel(this->m_ClProgram, "ckDMAS", &clErr); + break; + } + case BeamformingSettings::BeamformingAlgorithm::sDMAS: + { + this->m_PixelCalculation = clCreateKernel(this->m_ClProgram, "cksDMAS", &clErr); + break; + } + default: + { + MITK_INFO << "No beamforming algorithm specified, setting to DAS"; + this->m_PixelCalculation = clCreateKernel(this->m_ClProgram, "ckDAS", &clErr); + break; + } + } + buildErr |= CHECK_OCL_ERR( clErr ); + } + + CHECK_OCL_ERR(clErr); + + return (OclFilter::IsInitialized() && buildErr ); +} + +void mitk::PhotoacousticOCLBeamformingFilter::SetInput(mitk::Image::Pointer image) +{ + OclDataSetToDataSetFilter::SetInput(image); + + m_InputImage = image; + m_Conf.inputDim[0] = m_InputImage->GetDimension(0); + m_Conf.inputDim[1] = m_InputImage->GetDimension(1); + m_Conf.inputDim[2] = m_InputImage->GetDimension(2); +} + +void mitk::PhotoacousticOCLBeamformingFilter::SetInput(void* data, unsigned int* dimensions, unsigned int BpE) +{ + OclDataSetToDataSetFilter::SetInput(data, dimensions[0] * dimensions[1] * dimensions[2], BpE); + + m_Conf.inputDim[0] = dimensions[0]; + m_Conf.inputDim[1] = dimensions[1]; + m_Conf.inputDim[2] = dimensions[2]; +} + +mitk::Image::Pointer mitk::PhotoacousticOCLBeamformingFilter::GetOutputAsImage() +{ + mitk::Image::Pointer outputImage = mitk::Image::New(); + + if (m_Output->IsModified(GPU_DATA)) + { + void* pData = m_Output->TransferDataToCPU(m_CommandQue); + + const unsigned int dimension = 3; + unsigned int dimensions[3] = { (unsigned int)m_OutputDim[0], (unsigned int)m_OutputDim[1], (unsigned int)m_OutputDim[2] }; + + const mitk::SlicedGeometry3D::Pointer p_slg = m_InputImage->GetSlicedGeometry(); + + MITK_DEBUG << "Creating new MITK Image."; + + outputImage->Initialize(this->GetOutputType(), dimension, dimensions); + outputImage->SetSpacing(p_slg->GetSpacing()); + outputImage->SetImportVolume(pData, 0, 0, mitk::Image::ImportMemoryManagementType::ManageMemory); + } + + MITK_DEBUG << "Image Initialized."; + + return outputImage; +} + +void* mitk::PhotoacousticOCLBeamformingFilter::GetOutput() +{ + return OclDataSetToDataSetFilter::GetOutput(); +} +#endif diff --git a/Modules/PhotoacousticsAlgorithms/source/OpenCLFilter/mitkPhotoacousticOCLDelayCalculation.cpp b/Modules/PhotoacousticsAlgorithms/source/OpenCLFilter/mitkPhotoacousticOCLDelayCalculation.cpp new file mode 100644 index 0000000000..bbee18bc42 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/source/OpenCLFilter/mitkPhotoacousticOCLDelayCalculation.cpp @@ -0,0 +1,125 @@ +/*=================================================================== + +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 +#include "./OpenCLFilter/mitkPhotoacousticOCLDelayCalculation.h" +#include "usServiceReference.h" +#include "mitkImageReadAccessor.h" + +mitk::OCLDelayCalculation::OCLDelayCalculation() + : m_PixelCalculation(NULL) +{ + this->AddSourceFile("DelayCalculation.cl"); + this->m_FilterID = "DelayCalculation"; + + m_ChunkSize[0] = 128; + m_ChunkSize[1] = 128; + m_ChunkSize[2] = 8; + + this->Initialize(); +} + +mitk::OCLDelayCalculation::~OCLDelayCalculation() +{ + if (this->m_PixelCalculation) + { + clReleaseKernel(m_PixelCalculation); + } +} + +void mitk::OCLDelayCalculation::Update() +{ + //Check if context & program available + if (!this->Initialize()) + { + us::ServiceReference ref = GetModuleContext()->GetServiceReference(); + OclResourceService* resources = GetModuleContext()->GetService(ref); + + // clean-up also the resources + resources->InvalidateStorage(); + mitkThrow() << "Filter is not initialized. Cannot update."; + } + else { + // Execute + this->Execute(); + } +} + +void mitk::OCLDelayCalculation::Execute() +{ + cl_int clErr = 0; + + unsigned int gridDim[3] = { m_Conf.ReconstructionLines / 2, m_Conf.SamplesPerLine, 1 }; + m_BufferSize = gridDim[0] * gridDim[1] * 1; + + try + { + this->InitExecNoInput(this->m_PixelCalculation, gridDim, m_BufferSize, sizeof(unsigned short)); + } + catch (const mitk::Exception& e) + { + MITK_ERROR << "Caught exception while initializing Delay Calculation filter: " << e.what(); + return; + } + + // This calculation is the same for all kernels, so for performance reasons simply perform it here instead of within the kernels + if (m_Conf.DelayCalculationMethod == BeamformingSettings::DelayCalc::QuadApprox) + m_DelayMultiplicatorRaw = pow(1 / (m_Conf.TimeSpacing*m_Conf.SpeedOfSound) * m_Conf.Pitch * (float)m_Conf.TransducerElements / (float)m_Conf.inputDim[0], 2) / 2; + else if (m_Conf.DelayCalculationMethod == BeamformingSettings::DelayCalc::Spherical) + m_DelayMultiplicatorRaw = 1 / (m_Conf.TimeSpacing*m_Conf.SpeedOfSound) * (m_Conf.Pitch*(float)m_Conf.TransducerElements); + + // as openCL does not support bool as a kernel argument, we need to buffer this value in a char... + m_IsPAImage = m_Conf.isPhotoacousticImage; + + clErr = clSetKernelArg(this->m_PixelCalculation, 1, sizeof(cl_mem), &(this->m_UsedLines)); + clErr |= clSetKernelArg(this->m_PixelCalculation, 2, sizeof(cl_uint), &(this->m_Conf.inputDim[0])); + clErr |= clSetKernelArg(this->m_PixelCalculation, 3, sizeof(cl_uint), &(this->m_Conf.inputDim[1])); + clErr |= clSetKernelArg(this->m_PixelCalculation, 4, sizeof(cl_uint), &(this->m_Conf.ReconstructionLines)); + clErr |= clSetKernelArg(this->m_PixelCalculation, 5, sizeof(cl_uint), &(this->m_Conf.SamplesPerLine)); + clErr |= clSetKernelArg(this->m_PixelCalculation, 6, sizeof(cl_char), &(this->m_IsPAImage)); + clErr |= clSetKernelArg(this->m_PixelCalculation, 7, sizeof(cl_float), &(this->m_DelayMultiplicatorRaw)); + + CHECK_OCL_ERR(clErr); + + // execute the filter on a 3D NDRange + if (!this->ExecuteKernelChunksInBatches(m_PixelCalculation, 2, m_ChunkSize, 16, 50)) + mitkThrow() << "openCL Error when executing Kernel"; + // signalize the GPU-side data changed + m_Output->Modified(GPU_DATA); +} + +us::Module *mitk::OCLDelayCalculation::GetModule() +{ + return us::GetModuleContext()->GetModule(); +} + +bool mitk::OCLDelayCalculation::Initialize() +{ + bool buildErr = true; + cl_int clErr = 0; + + if (OclFilter::Initialize()) + { + if(m_Conf.DelayCalculationMethod == BeamformingSettings::DelayCalc::QuadApprox) + this->m_PixelCalculation = clCreateKernel(this->m_ClProgram, "ckDelayCalculationQuad", &clErr); + if (m_Conf.DelayCalculationMethod == BeamformingSettings::DelayCalc::Spherical) + this->m_PixelCalculation = clCreateKernel(this->m_ClProgram, "ckDelayCalculationSphe", &clErr); + buildErr |= CHECK_OCL_ERR(clErr); + } + return (OclFilter::IsInitialized() && buildErr); +} \ No newline at end of file diff --git a/Modules/PhotoacousticsAlgorithms/source/OpenCLFilter/mitkPhotoacousticOCLUsedLinesCalculation.cpp b/Modules/PhotoacousticsAlgorithms/source/OpenCLFilter/mitkPhotoacousticOCLUsedLinesCalculation.cpp new file mode 100644 index 0000000000..c44b1a98d7 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/source/OpenCLFilter/mitkPhotoacousticOCLUsedLinesCalculation.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. + +===================================================================*/ +#if defined(PHOTOACOUSTICS_USE_GPU) || DOXYGEN +#define _USE_MATH_DEFINES + +#include +#include "./OpenCLFilter/mitkPhotoacousticOCLUsedLinesCalculation.h" +#include "usServiceReference.h" +#include "mitkImageReadAccessor.h" + +mitk::OCLUsedLinesCalculation::OCLUsedLinesCalculation() + : m_PixelCalculation(NULL) +{ + this->AddSourceFile("UsedLinesCalculation.cl"); + this->m_FilterID = "UsedLinesCalculation"; + + m_ChunkSize[0] = 128; + m_ChunkSize[1] = 128; + m_ChunkSize[2] = 8; + + this->Initialize(); +} + +mitk::OCLUsedLinesCalculation::~OCLUsedLinesCalculation() +{ + if (this->m_PixelCalculation) + { + clReleaseKernel(m_PixelCalculation); + } +} + +void mitk::OCLUsedLinesCalculation::Update() +{ + //Check if context & program available + if (!this->Initialize()) + { + us::ServiceReference ref = GetModuleContext()->GetServiceReference(); + OclResourceService* resources = GetModuleContext()->GetService(ref); + + // clean-up also the resources + resources->InvalidateStorage(); + mitkThrow() << "Filter is not initialized. Cannot update."; + } + else { + // Execute + this->Execute(); + } +} + +void mitk::OCLUsedLinesCalculation::Execute() +{ + cl_int clErr = 0; + + unsigned int gridDim[3] = { m_Conf.ReconstructionLines, m_Conf.SamplesPerLine, 1 }; + size_t outputSize = gridDim[0] * gridDim[1] * 3; + + try + { + this->InitExecNoInput(this->m_PixelCalculation, gridDim, outputSize, sizeof(unsigned short)); + } + catch (const mitk::Exception& e) + { + MITK_ERROR << "Caught exception while initializing UsedLines filter: " << e.what(); + return; + } + + // This calculation is the same for all kernels, so for performance reasons simply perform it here instead of within the kernels + m_part = (tan(m_Conf.Angle / 360 * 2 * M_PI) * ((m_Conf.SpeedOfSound * m_Conf.TimeSpacing)) / (m_Conf.Pitch * m_Conf.TransducerElements)) * m_Conf.inputDim[0]; + + clErr = clSetKernelArg(this->m_PixelCalculation, 1, sizeof(cl_float), &(this->m_part)); + clErr |= clSetKernelArg(this->m_PixelCalculation, 2, sizeof(cl_uint), &(this->m_Conf.inputDim[0])); + clErr |= clSetKernelArg(this->m_PixelCalculation, 3, sizeof(cl_uint), &(this->m_Conf.inputDim[1])); + clErr |= clSetKernelArg(this->m_PixelCalculation, 4, sizeof(cl_uint), &(this->m_Conf.ReconstructionLines)); + clErr |= clSetKernelArg(this->m_PixelCalculation, 5, sizeof(cl_uint), &(this->m_Conf.SamplesPerLine)); + + CHECK_OCL_ERR(clErr); + + // execute the filter on a 2D NDRange + if (!this->ExecuteKernelChunksInBatches(m_PixelCalculation, 2, m_ChunkSize, 16, 50)) + mitkThrow() << "openCL Error when executing Kernel"; + + // signalize the GPU-side data changed + m_Output->Modified(GPU_DATA); +} + +us::Module *mitk::OCLUsedLinesCalculation::GetModule() +{ + return us::GetModuleContext()->GetModule(); +} + +bool mitk::OCLUsedLinesCalculation::Initialize() +{ + bool buildErr = true; + cl_int clErr = 0; + + if (OclFilter::Initialize()) + { + this->m_PixelCalculation = clCreateKernel(this->m_ClProgram, "ckUsedLines", &clErr); + buildErr |= CHECK_OCL_ERR(clErr); + } + return (OclFilter::IsInitialized() && buildErr); +} +#endif diff --git a/Modules/PhotoacousticsAlgorithms/source/mitkPhotoacousticBeamformingFilter.cpp b/Modules/PhotoacousticsAlgorithms/source/mitkPhotoacousticBeamformingFilter.cpp new file mode 100644 index 0000000000..9fff61a04e --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/source/mitkPhotoacousticBeamformingFilter.cpp @@ -0,0 +1,803 @@ +/*=================================================================== +mitkPhotoacousticBeamformingFilter +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 "mitkProperties.h" +#include "mitkImageReadAccessor.h" +#include +#include +#include +#include +#include +#include +#include "mitkImageCast.h" +#include "mitkPhotoacousticBeamformingFilter.h" + +mitk::BeamformingFilter::BeamformingFilter() : m_OutputData(nullptr), m_InputData(nullptr), m_Message("noMessage") +{ + this->SetNumberOfIndexedInputs(1); + this->SetNumberOfRequiredInputs(1); + + m_ProgressHandle = [](int, std::string) {}; + + m_BeamformingOclFilter = mitk::PhotoacousticOCLBeamformingFilter::New(); + + m_VonHannFunction = VonHannFunction(m_Conf.apodizationArraySize); + m_HammFunction = HammFunction(m_Conf.apodizationArraySize); + m_BoxFunction = BoxFunction(m_Conf.apodizationArraySize); +} + +void mitk::BeamformingFilter::SetProgressHandle(std::function progressHandle) +{ + m_ProgressHandle = progressHandle; +} + +mitk::BeamformingFilter::~BeamformingFilter() +{ + delete[] m_VonHannFunction; + delete[] m_HammFunction; + delete[] m_BoxFunction; +} + +void mitk::BeamformingFilter::GenerateInputRequestedRegion() +{ + Superclass::GenerateInputRequestedRegion(); + + mitk::Image* output = this->GetOutput(); + mitk::Image* input = const_cast (this->GetInput()); + if (!output->IsInitialized()) + { + return; + } + + input->SetRequestedRegionToLargestPossibleRegion(); + //GenerateTimeInInputRegion(output, input); +} + +void mitk::BeamformingFilter::GenerateOutputInformation() +{ + mitk::Image::ConstPointer input = this->GetInput(); + mitk::Image::Pointer output = this->GetOutput(); + + if ((output->IsInitialized()) && (this->GetMTime() <= m_TimeOfHeaderInitialization.GetMTime())) + return; + + itkDebugMacro(<< "GenerateOutputInformation()"); + + unsigned int dim[] = { m_Conf.ReconstructionLines, m_Conf.SamplesPerLine, input->GetDimension(2) }; + output->Initialize(mitk::MakeScalarPixelType(), 3, dim); + + mitk::Vector3D spacing; + spacing[0] = m_Conf.Pitch * m_Conf.TransducerElements * 1000 / m_Conf.ReconstructionLines; + spacing[1] = (m_Conf.TimeSpacing * m_Conf.inputDim[1]) / 2 * m_Conf.SpeedOfSound * 1000 / m_Conf.SamplesPerLine; + spacing[2] = 1; + + output->GetGeometry()->SetSpacing(spacing); + output->GetGeometry()->Modified(); + output->SetPropertyList(input->GetPropertyList()->Clone()); + + m_TimeOfHeaderInitialization.Modified(); +} + + +void mitk::BeamformingFilter::GenerateData() +{ + GenerateOutputInformation(); + mitk::Image::Pointer input = this->GetInput(); + mitk::Image::Pointer output = this->GetOutput(); + + if (!output->IsInitialized()) + return; + + float* ApodWindow; + if (m_ConfOld.apodizationArraySize != m_Conf.apodizationArraySize) + { + delete[] m_VonHannFunction; + delete[] m_HammFunction; + delete[] m_BoxFunction; + m_VonHannFunction = VonHannFunction(m_Conf.apodizationArraySize); + m_HammFunction = HammFunction(m_Conf.apodizationArraySize); + m_BoxFunction = BoxFunction(m_Conf.apodizationArraySize); + + m_ConfOld = m_Conf; + } + + // set the appropiate apodization window + switch (m_Conf.Apod) + { + case BeamformingSettings::Apodization::Hann: + ApodWindow = m_VonHannFunction; + break; + case BeamformingSettings::Apodization::Hamm: + ApodWindow = m_HammFunction; + break; + case BeamformingSettings::Apodization::Box: + ApodWindow = m_BoxFunction; + break; + default: + ApodWindow = m_BoxFunction; + break; + } + + auto begin = std::chrono::high_resolution_clock::now(); // debbuging the performance... + + if (!m_Conf.UseGPU) + { + int progInterval = output->GetDimension(2) / 20 > 1 ? output->GetDimension(2) / 20 : 1; + // the interval at which we update the gui progress bar + + float inputDim[2] = { (float)input->GetDimension(0), (float)input->GetDimension(1) }; + float outputDim[2] = { (float)output->GetDimension(0), (float)output->GetDimension(1) }; + + for (unsigned int i = 0; i < output->GetDimension(2); ++i) // seperate Slices should get Beamforming seperately applied + { + mitk::ImageReadAccessor inputReadAccessor(input, input->GetSliceData(i)); + + // first, we check whether the dara is float, other formats are unsupported + if (input->GetPixelType().GetTypeAsString() == "scalar (float)" || input->GetPixelType().GetTypeAsString() == " (float)") + { + m_InputData = (float*)inputReadAccessor.GetData(); + } + else + { + MITK_INFO << "Pixel type is not float, abort"; + return; + } + + m_OutputData = new float[m_Conf.ReconstructionLines*m_Conf.SamplesPerLine]; + + // fill the image with zeros + for (int l = 0; l < outputDim[0]; ++l) + { + for (int s = 0; s < outputDim[1]; ++s) + { + m_OutputData[l*(short)outputDim[1] + s] = 0; + } + } + + std::thread *threads = new std::thread[(short)outputDim[0]]; + + // every line will be beamformed in a seperate thread + if (m_Conf.Algorithm == BeamformingSettings::BeamformingAlgorithm::DAS) + { + if (m_Conf.DelayCalculationMethod == BeamformingSettings::DelayCalc::QuadApprox) + { + for (short line = 0; line < outputDim[0]; ++line) + { + threads[line] = std::thread(&BeamformingFilter::DASQuadraticLine, this, m_InputData, m_OutputData, inputDim, outputDim, line, ApodWindow, m_Conf.apodizationArraySize); + } + } + else if (m_Conf.DelayCalculationMethod == BeamformingSettings::DelayCalc::Spherical) + { + for (short line = 0; line < outputDim[0]; ++line) + { + threads[line] = std::thread(&BeamformingFilter::DASSphericalLine, this, m_InputData, m_OutputData, inputDim, outputDim, line, ApodWindow, m_Conf.apodizationArraySize); + } + } + } + else if (m_Conf.Algorithm == BeamformingSettings::BeamformingAlgorithm::DMAS) + { + if (m_Conf.DelayCalculationMethod == BeamformingSettings::DelayCalc::QuadApprox) + { + for (short line = 0; line < outputDim[0]; ++line) + { + threads[line] = std::thread(&BeamformingFilter::DMASQuadraticLine, this, m_InputData, m_OutputData, inputDim, outputDim, line, ApodWindow, m_Conf.apodizationArraySize); + } + } + else if (m_Conf.DelayCalculationMethod == BeamformingSettings::DelayCalc::Spherical) + { + for (short line = 0; line < outputDim[0]; ++line) + { + threads[line] = std::thread(&BeamformingFilter::DMASSphericalLine, this, m_InputData, m_OutputData, inputDim, outputDim, line, ApodWindow, m_Conf.apodizationArraySize); + } + } + } + else if (m_Conf.Algorithm == BeamformingSettings::BeamformingAlgorithm::sDMAS) + { + if (m_Conf.DelayCalculationMethod == BeamformingSettings::DelayCalc::QuadApprox) + { + for (short line = 0; line < outputDim[0]; ++line) + { + threads[line] = std::thread(&BeamformingFilter::sDMASQuadraticLine, this, m_InputData, m_OutputData, inputDim, outputDim, line, ApodWindow, m_Conf.apodizationArraySize); + } + } + else if (m_Conf.DelayCalculationMethod == BeamformingSettings::DelayCalc::Spherical) + { + for (short line = 0; line < outputDim[0]; ++line) + { + threads[line] = std::thread(&BeamformingFilter::sDMASSphericalLine, this, m_InputData, m_OutputData, inputDim, outputDim, line, ApodWindow, m_Conf.apodizationArraySize); + } + } + } + // wait for all lines to finish + for (short line = 0; line < outputDim[0]; ++line) + { + threads[line].join(); + } + + output->SetSlice(m_OutputData, i); + + if (i % progInterval == 0) + m_ProgressHandle((int)((i + 1) / (float)output->GetDimension(2) * 100), "performing reconstruction"); + + delete[] m_OutputData; + m_OutputData = nullptr; + m_InputData = nullptr; + } + } + #if defined(PHOTOACOUSTICS_USE_GPU) || DOXYGEN + else + { + try + { + // first, we check whether the data is float, other formats are unsupported + if (!(input->GetPixelType().GetTypeAsString() == "scalar (float)" || input->GetPixelType().GetTypeAsString() == " (float)")) + { + MITK_ERROR << "Pixel type is not float, abort"; + return; + } + + long availableMemory = m_BeamformingOclFilter->GetDeviceMemory(); + + unsigned int batchSize = 16; + unsigned int batches = (unsigned int)((float)input->GetDimension(2)/batchSize) + (input->GetDimension(2)%batchSize > 0); + + unsigned int batchDim[] = { input->GetDimension(0), input->GetDimension(1), batchSize }; + unsigned int batchDimLast[] = { input->GetDimension(0), input->GetDimension(1), input->GetDimension(2) % batchSize }; + + // the following safeguard is probably only needed for absurdly small GPU memory + for (batchSize = 16; + (long)(batchDim[0] * batchDim[1]) * 4 + // Input image (float) + (long)(m_Conf.ReconstructionLines * m_Conf.SamplesPerLine) * 4 // Output image (float) + > availableMemory - + (long)(m_Conf.ReconstructionLines / 2 * m_Conf.SamplesPerLine) * 2 - // Delays buffer (unsigned short) + (long)(m_Conf.ReconstructionLines * m_Conf.SamplesPerLine) * 3 * 2 - // UsedLines buffer (unsigned short) + 100 * 1024; // 100 MB buffer for local data, system purposes etc + --batchSize) + {} + if (batchSize < 1) + { + MITK_ERROR << "device memory too small for GPU beamforming"; + return; + } + + mitk::ImageReadAccessor copy(input); + + for(unsigned int i = 0; i < batches; ++i) + { + m_ProgressHandle(input->GetDimension(2)/batches * i, "performing reconstruction"); + + mitk::Image::Pointer inputBatch = mitk::Image::New(); + if(i == batches - 1 && (input->GetDimension(2)%batchSize > 0)) + { + inputBatch->Initialize(mitk::MakeScalarPixelType(), 3, batchDimLast); + m_Conf.inputDim[2] = batchDimLast[2]; + } + else + { + inputBatch->Initialize(mitk::MakeScalarPixelType(), 3, batchDim); + m_Conf.inputDim[2] = batchDim[2]; + } + + inputBatch->SetSpacing(input->GetGeometry()->GetSpacing()); + + inputBatch->SetImportVolume(&(((float*)copy.GetData())[input->GetDimension(0) * input->GetDimension(1) * batchSize * i])); + + m_BeamformingOclFilter->SetApodisation(ApodWindow, m_Conf.apodizationArraySize); + m_BeamformingOclFilter->SetConfig(m_Conf); + m_BeamformingOclFilter->SetInput(inputBatch); + m_BeamformingOclFilter->Update(); + + void* out = m_BeamformingOclFilter->GetOutput(); + + for(unsigned int slice = 0; slice < m_Conf.inputDim[2]; ++slice) + { + output->SetImportSlice( + &(((float*)out)[m_Conf.ReconstructionLines * m_Conf.SamplesPerLine * slice]), + batchSize * i + slice, 0, 0, mitk::Image::ImportMemoryManagementType::CopyMemory); + } + } + } + catch (mitk::Exception &e) + { + std::string errorMessage = "Caught unexpected exception "; + errorMessage.append(e.what()); + MITK_ERROR << errorMessage; + + float* dummyData = new float[m_Conf.ReconstructionLines * m_Conf.SamplesPerLine * m_Conf.inputDim[2]]; + output->SetImportVolume(dummyData, 0, 0, mitk::Image::ImportMemoryManagementType::ManageMemory); + + m_Message = "An openCL error occurred; all GPU operations in this and the next session may be corrupted."; + } + } + #endif + m_TimeOfHeaderInitialization.Modified(); + + auto end = std::chrono::high_resolution_clock::now(); + MITK_INFO << "Beamforming of " << output->GetDimension(2) << " Images completed in " << ((float)std::chrono::duration_cast(end - begin).count()) / 1000000 << "ms" << std::endl; +} + +float* mitk::BeamformingFilter::VonHannFunction(int samples) +{ + float* ApodWindow = new float[samples]; + + for (int n = 0; n < samples; ++n) + { + ApodWindow[n] = (1 - cos(2 * M_PI * n / (samples - 1))) / 2; + } + + return ApodWindow; +} + +float* mitk::BeamformingFilter::HammFunction(int samples) +{ + float* ApodWindow = new float[samples]; + + for (int n = 0; n < samples; ++n) + { + ApodWindow[n] = 0.54 - 0.46*cos(2 * M_PI*n / (samples - 1)); + } + + return ApodWindow; +} + +float* mitk::BeamformingFilter::BoxFunction(int samples) +{ + float* ApodWindow = new float[samples]; + + for (int n = 0; n < samples; ++n) + { + ApodWindow[n] = 1; + } + + return ApodWindow; +} + +void mitk::BeamformingFilter::DASQuadraticLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize) +{ + float& inputS = inputDim[1]; + float& inputL = inputDim[0]; + + float& outputS = outputDim[1]; + float& outputL = outputDim[0]; + + short AddSample = 0; + short maxLine = 0; + short minLine = 0; + float delayMultiplicator = 0; + float l_i = 0; + float s_i = 0; + + float part = 0.07 * inputL; + float tan_phi = std::tan(m_Conf.Angle / 360 * 2 * M_PI); + float part_multiplicator = tan_phi * m_Conf.TimeSpacing * m_Conf.SpeedOfSound / m_Conf.Pitch * inputL / m_Conf.TransducerElements; + float apod_mult = 1; + + short usedLines = (maxLine - minLine); + + //quadratic delay + l_i = line / outputL * inputL; + + for (short sample = 0; sample < outputS; ++sample) + { + s_i = (float)sample / outputS * inputS / 2; + + part = part_multiplicator*s_i; + + if (part < 1) + part = 1; + + maxLine = (short)std::min((l_i + part) + 1, inputL); + minLine = (short)std::max((l_i - part), 0.0f); + usedLines = (maxLine - minLine); + + apod_mult = (float)apodArraySize / (float)usedLines; + + delayMultiplicator = pow((1 / (m_Conf.TimeSpacing*m_Conf.SpeedOfSound) * (m_Conf.Pitch*m_Conf.TransducerElements) / inputL), 2) / s_i / 2; + + for (short l_s = minLine; l_s < maxLine; ++l_s) + { + AddSample = delayMultiplicator * pow((l_s - l_i), 2) + s_i + (1 - m_Conf.isPhotoacousticImage)*s_i; + if (AddSample < inputS && AddSample >= 0) + output[sample*(short)outputL + line] += input[l_s + AddSample*(short)inputL] * apodisation[(short)((l_s - minLine)*apod_mult)]; + else + --usedLines; + } + output[sample*(short)outputL + line] = output[sample*(short)outputL + line] / usedLines; + } +} + +void mitk::BeamformingFilter::DASSphericalLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize) +{ + float& inputS = inputDim[1]; + float& inputL = inputDim[0]; + + float& outputS = outputDim[1]; + float& outputL = outputDim[0]; + + short AddSample = 0; + short maxLine = 0; + short minLine = 0; + float l_i = 0; + float s_i = 0; + + float part = 0.07 * inputL; + float tan_phi = std::tan(m_Conf.Angle / 360 * 2 * M_PI); + float part_multiplicator = tan_phi * m_Conf.TimeSpacing * m_Conf.SpeedOfSound / m_Conf.Pitch * inputL / (float)m_Conf.TransducerElements; + float apod_mult = 1; + + short usedLines = (maxLine - minLine); + + //exact delay + + l_i = (float)line / outputL * inputL; + + for (short sample = 0; sample < outputS; ++sample) + { + s_i = (float)sample / outputS * inputS / 2; + + part = part_multiplicator*s_i; + + if (part < 1) + part = 1; + + maxLine = (short)std::min((l_i + part) + 1, inputL); + minLine = (short)std::max((l_i - part), 0.0f); + usedLines = (maxLine - minLine); + + apod_mult = (float)apodArraySize / (float)usedLines; + + for (short l_s = minLine; l_s < maxLine; ++l_s) + { + AddSample = (int)sqrt( + pow(s_i, 2) + + + pow((1 / (m_Conf.TimeSpacing*m_Conf.SpeedOfSound) * (((float)l_s - l_i)*m_Conf.Pitch*(float)m_Conf.TransducerElements) / inputL), 2) + ) + (1 - m_Conf.isPhotoacousticImage)*s_i; + if (AddSample < inputS && AddSample >= 0) + output[sample*(short)outputL + line] += input[l_s + AddSample*(short)inputL] * apodisation[(short)((l_s - minLine)*apod_mult)]; + else + --usedLines; + } + output[sample*(short)outputL + line] = output[sample*(short)outputL + line] / usedLines; + } +} + + +void mitk::BeamformingFilter::DMASQuadraticLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize) +{ + float& inputS = inputDim[1]; + float& inputL = inputDim[0]; + + float& outputS = outputDim[1]; + float& outputL = outputDim[0]; + + short maxLine = 0; + short minLine = 0; + float delayMultiplicator = 0; + float l_i = 0; + float s_i = 0; + + float part = 0.07 * inputL; + float tan_phi = std::tan(m_Conf.Angle / 360 * 2 * M_PI); + float part_multiplicator = tan_phi * m_Conf.TimeSpacing * m_Conf.SpeedOfSound / m_Conf.Pitch * inputL / (float)m_Conf.TransducerElements; + float apod_mult = 1; + + float mult = 0; + short usedLines = (maxLine - minLine); + + //quadratic delay + l_i = line / outputL * inputL; + + for (short sample = 0; sample < outputS; ++sample) + { + s_i = sample / outputS * inputS / 2; + + part = part_multiplicator*s_i; + + if (part < 1) + part = 1; + + maxLine = (short)std::min((l_i + part) + 1, inputL); + minLine = (short)std::max((l_i - part), 0.0f); + usedLines = (maxLine - minLine); + + apod_mult = (float)apodArraySize / (float)usedLines; + + delayMultiplicator = pow((1 / (m_Conf.TimeSpacing*m_Conf.SpeedOfSound) * (m_Conf.Pitch*m_Conf.TransducerElements) / inputL), 2) / s_i / 2; + + //calculate the AddSamples beforehand to save some time + short* AddSample = new short[maxLine - minLine]; + for (short l_s = 0; l_s < maxLine - minLine; ++l_s) + { + AddSample[l_s] = (short)(delayMultiplicator * pow((minLine + l_s - l_i), 2) + s_i) + (1 - m_Conf.isPhotoacousticImage)*s_i; + } + + float s_1 = 0; + float s_2 = 0; + + for (short l_s1 = minLine; l_s1 < maxLine - 1; ++l_s1) + { + if (AddSample[l_s1 - minLine] < inputS && AddSample[l_s1 - minLine] >= 0) + { + for (short l_s2 = l_s1 + 1; l_s2 < maxLine; ++l_s2) + { + if (AddSample[l_s2 - minLine] < inputS && AddSample[l_s2 - minLine] >= 0) + { + s_2 = input[l_s2 + AddSample[l_s2 - minLine] * (short)inputL]; + s_1 = input[l_s1 + AddSample[l_s1 - minLine] * (short)inputL]; + + mult = s_2 * apodisation[(int)((l_s2 - minLine)*apod_mult)] * s_1 * apodisation[(int)((l_s1 - minLine)*apod_mult)]; + output[sample*(short)outputL + line] += sqrt(fabs(mult)) * ((mult > 0) - (mult < 0)); + } + } + } + else + --usedLines; + } + + output[sample*(short)outputL + line] = output[sample*(short)outputL + line] / (float)(pow(usedLines, 2) - (usedLines - 1)); + + delete[] AddSample; + } +} + +void mitk::BeamformingFilter::DMASSphericalLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize) +{ + float& inputS = inputDim[1]; + float& inputL = inputDim[0]; + + float& outputS = outputDim[1]; + float& outputL = outputDim[0]; + + short maxLine = 0; + short minLine = 0; + float l_i = 0; + float s_i = 0; + + float part = 0.07 * inputL; + float tan_phi = std::tan(m_Conf.Angle / 360 * 2 * M_PI); + float part_multiplicator = tan_phi * m_Conf.TimeSpacing * m_Conf.SpeedOfSound / m_Conf.Pitch * inputL / (float)m_Conf.TransducerElements; + float apod_mult = 1; + + float mult = 0; + + short usedLines = (maxLine - minLine); + + //exact delay + + l_i = (float)line / outputL * inputL; + + for (short sample = 0; sample < outputS; ++sample) + { + s_i = (float)sample / outputS * inputS / 2; + + part = part_multiplicator*s_i; + + if (part < 1) + part = 1; + + maxLine = (short)std::min((l_i + part) + 1, inputL); + minLine = (short)std::max((l_i - part), 0.0f); + usedLines = (maxLine - minLine); + + apod_mult = (float)apodArraySize / (float)usedLines; + + //calculate the AddSamples beforehand to save some time + short* AddSample = new short[maxLine - minLine]; + for (short l_s = 0; l_s < maxLine - minLine; ++l_s) + { + AddSample[l_s] = (short)sqrt( + pow(s_i, 2) + + + pow((1 / (m_Conf.TimeSpacing*m_Conf.SpeedOfSound) * (((float)minLine + (float)l_s - l_i)*m_Conf.Pitch*(float)m_Conf.TransducerElements) / inputL), 2) + ) + (1 - m_Conf.isPhotoacousticImage)*s_i; + } + + float s_1 = 0; + float s_2 = 0; + + for (short l_s1 = minLine; l_s1 < maxLine - 1; ++l_s1) + { + if (AddSample[l_s1 - minLine] < inputS && AddSample[l_s1 - minLine] >= 0) + { + for (short l_s2 = l_s1 + 1; l_s2 < maxLine; ++l_s2) + { + if (AddSample[l_s2 - minLine] < inputS && AddSample[l_s2 - minLine] >= 0) + { + s_2 = input[l_s2 + AddSample[l_s2 - minLine] * (short)inputL]; + s_1 = input[l_s1 + AddSample[l_s1 - minLine] * (short)inputL]; + + mult = s_2 * apodisation[(int)((l_s2 - minLine)*apod_mult)] * s_1 * apodisation[(int)((l_s1 - minLine)*apod_mult)]; + output[sample*(short)outputL + line] += sqrt(fabs(mult)) * ((mult > 0) - (mult < 0)); + } + } + } + else + --usedLines; + } + + output[sample*(short)outputL + line] = output[sample*(short)outputL + line] / (float)(pow(usedLines, 2) - (usedLines - 1)); + + delete[] AddSample; + } +} + +void mitk::BeamformingFilter::sDMASQuadraticLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize) +{ + float& inputS = inputDim[1]; + float& inputL = inputDim[0]; + + float& outputS = outputDim[1]; + float& outputL = outputDim[0]; + + short maxLine = 0; + short minLine = 0; + float delayMultiplicator = 0; + float l_i = 0; + float s_i = 0; + + float part = 0.07 * inputL; + float tan_phi = std::tan(m_Conf.Angle / 360 * 2 * M_PI); + float part_multiplicator = tan_phi * m_Conf.TimeSpacing * m_Conf.SpeedOfSound / m_Conf.Pitch * inputL / (float)m_Conf.TransducerElements; + float apod_mult = 1; + + float mult = 0; + short usedLines = (maxLine - minLine); + + //quadratic delay + l_i = line / outputL * inputL; + + for (short sample = 0; sample < outputS; ++sample) + { + s_i = sample / outputS * inputS / 2; + + part = part_multiplicator*s_i; + + if (part < 1) + part = 1; + + maxLine = (short)std::min((l_i + part) + 1, inputL); + minLine = (short)std::max((l_i - part), 0.0f); + usedLines = (maxLine - minLine); + + apod_mult = (float)apodArraySize / (float)usedLines; + + delayMultiplicator = pow((1 / (m_Conf.TimeSpacing*m_Conf.SpeedOfSound) * (m_Conf.Pitch*m_Conf.TransducerElements) / inputL), 2) / s_i / 2; + + //calculate the AddSamples beforehand to save some time + short* AddSample = new short[maxLine - minLine]; + for (short l_s = 0; l_s < maxLine - minLine; ++l_s) + { + AddSample[l_s] = (short)(delayMultiplicator * pow((minLine + l_s - l_i), 2) + s_i) + (1 - m_Conf.isPhotoacousticImage)*s_i; + } + + float s_1 = 0; + float s_2 = 0; + float sign = 0; + + for (short l_s1 = minLine; l_s1 < maxLine - 1; ++l_s1) + { + if (AddSample[l_s1 - minLine] < inputS && AddSample[l_s1 - minLine] >= 0) + { + s_1 = input[l_s1 + AddSample[l_s1 - minLine] * (short)inputL]; + sign += s_1; + + for (short l_s2 = l_s1 + 1; l_s2 < maxLine; ++l_s2) + { + if (AddSample[l_s2 - minLine] < inputS && AddSample[l_s2 - minLine] >= 0) + { + s_2 = input[l_s2 + AddSample[l_s2 - minLine] * (short)inputL]; + + mult = s_2 * apodisation[(int)((l_s2 - minLine)*apod_mult)] * s_1 * apodisation[(int)((l_s1 - minLine)*apod_mult)]; + output[sample*(short)outputL + line] += sqrt(fabs(mult)) * ((mult > 0) - (mult < 0)); + } + } + } + else + --usedLines; + } + + output[sample*(short)outputL + line] = output[sample*(short)outputL + line] / (float)(pow(usedLines, 2) - (usedLines - 1)) * ((sign > 0) - (sign < 0)); + + delete[] AddSample; + } +} + +void mitk::BeamformingFilter::sDMASSphericalLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize) +{ + float& inputS = inputDim[1]; + float& inputL = inputDim[0]; + + float& outputS = outputDim[1]; + float& outputL = outputDim[0]; + + short maxLine = 0; + short minLine = 0; + float l_i = 0; + float s_i = 0; + + float part = 0.07 * inputL; + float tan_phi = std::tan(m_Conf.Angle / 360 * 2 * M_PI); + float part_multiplicator = tan_phi * m_Conf.TimeSpacing * m_Conf.SpeedOfSound / m_Conf.Pitch * inputL / (float)m_Conf.TransducerElements; + float apod_mult = 1; + + float mult = 0; + + short usedLines = (maxLine - minLine); + + //exact delay + + l_i = (float)line / outputL * inputL; + + for (short sample = 0; sample < outputS; ++sample) + { + s_i = (float)sample / outputS * inputS / 2; + + part = part_multiplicator*s_i; + + if (part < 1) + part = 1; + + maxLine = (short)std::min((l_i + part) + 1, inputL); + minLine = (short)std::max((l_i - part), 0.0f); + usedLines = (maxLine - minLine); + + apod_mult = (float)apodArraySize / (float)usedLines; + + //calculate the AddSamples beforehand to save some time + short* AddSample = new short[maxLine - minLine]; + for (short l_s = 0; l_s < maxLine - minLine; ++l_s) + { + AddSample[l_s] = (short)sqrt( + pow(s_i, 2) + + + pow((1 / (m_Conf.TimeSpacing*m_Conf.SpeedOfSound) * (((float)minLine + (float)l_s - l_i)*m_Conf.Pitch*(float)m_Conf.TransducerElements) / inputL), 2) + ) + (1 - m_Conf.isPhotoacousticImage)*s_i; + } + + float s_1 = 0; + float s_2 = 0; + float sign = 0; + + for (short l_s1 = minLine; l_s1 < maxLine - 1; ++l_s1) + { + if (AddSample[l_s1 - minLine] < inputS && AddSample[l_s1 - minLine] >= 0) + { + s_1 = input[l_s1 + AddSample[l_s1 - minLine] * (short)inputL]; + sign += s_1; + + for (short l_s2 = l_s1 + 1; l_s2 < maxLine; ++l_s2) + { + if (AddSample[l_s2 - minLine] < inputS && AddSample[l_s2 - minLine] >= 0) + { + s_2 = input[l_s2 + AddSample[l_s2 - minLine] * (short)inputL]; + + mult = s_2 * apodisation[(int)((l_s2 - minLine)*apod_mult)] * s_1 * apodisation[(int)((l_s1 - minLine)*apod_mult)]; + output[sample*(short)outputL + line] += sqrt(fabs(mult)) * ((mult > 0) - (mult < 0)); + } + } + } + else + --usedLines; + } + + output[sample*(short)outputL + line] = output[sample*(short)outputL + line] / (float)(pow(usedLines, 2) - (usedLines - 1)) * ((sign > 0) - (sign < 0)); + + delete[] AddSample; + } +} diff --git a/Modules/PhotoacousticsAlgorithms/mitkPhotoacousticImage.cpp b/Modules/PhotoacousticsAlgorithms/source/mitkPhotoacousticImage.cpp similarity index 72% copy from Modules/PhotoacousticsAlgorithms/mitkPhotoacousticImage.cpp copy to Modules/PhotoacousticsAlgorithms/source/mitkPhotoacousticImage.cpp index 9ba451e9cd..c74336ba67 100644 --- a/Modules/PhotoacousticsAlgorithms/mitkPhotoacousticImage.cpp +++ b/Modules/PhotoacousticsAlgorithms/source/mitkPhotoacousticImage.cpp @@ -1,641 +1,541 @@ /*=================================================================== 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 #include "mitkPhotoacousticImage.h" -#include "itkBModeImageFilter.h" -#include "itkPhotoacousticBModeImageFilter.h" +#include "../ITKFilter/ITKUltrasound/itkBModeImageFilter.h" +#include "../ITKFilter/itkPhotoacousticBModeImageFilter.h" #include "mitkImageCast.h" #include "mitkITKImageImport.h" #include "mitkPhotoacousticBeamformingFilter.h" #include #include -#include +#include "./OpenCLFilter/mitkPhotoacousticBModeFilter.h" // itk dependencies #include "itkImage.h" #include "itkResampleImageFilter.h" #include "itkCastImageFilter.h" #include "itkCropImageFilter.h" #include "itkRescaleIntensityImageFilter.h" #include "itkIntensityWindowingImageFilter.h" #include #include "itkMultiplyImageFilter.h" #include "itkBSplineInterpolateImageFunction.h" #include // needed itk image filters #include "mitkITKImageImport.h" #include "itkFFTShiftImageFilter.h" #include "itkMultiplyImageFilter.h" #include "itkComplexToModulusImageFilter.h" #include -#include "itkFFT1DComplexConjugateToRealImageFilter.h" -#include "itkFFT1DRealToComplexConjugateImageFilter.h" +#include "../ITKFilter/ITKUltrasound/itkFFT1DComplexConjugateToRealImageFilter.h" +#include "../ITKFilter/ITKUltrasound/itkFFT1DRealToComplexConjugateImageFilter.h" -mitk::PhotoacousticImage::PhotoacousticImage() +mitk::PhotoacousticImage::PhotoacousticImage() : m_BeamformingFilter(BeamformingFilter::New()) { MITK_INFO << "[PhotoacousticImage Debug] created that image"; } mitk::PhotoacousticImage::~PhotoacousticImage() { MITK_INFO << "[PhotoacousticImage Debug] destroyed that image"; } -mitk::Image::Pointer mitk::PhotoacousticImage::ApplyBmodeFilter(mitk::Image::Pointer inputImage, BModeMethod method, bool UseLogFilter, float resampleSpacing) +mitk::Image::Pointer mitk::PhotoacousticImage::ApplyBmodeFilter(mitk::Image::Pointer inputImage, BModeMethod method, bool UseGPU, bool UseLogFilter, float resampleSpacing) { // the image needs to be of floating point type for the envelope filter to work; the casting is done automatically by the CastToItkImage typedef itk::Image< float, 3 > itkFloatImageType; typedef itk::IdentityTransform TransformType; if (method == BModeMethod::Abs) { - auto input = ApplyCropping(inputImage, 0, 0, 0, 0, 0, inputImage->GetDimension(2) - 1); - PhotoacousticBModeFilter::Pointer filter = PhotoacousticBModeFilter::New(); - filter->SetParameters(UseLogFilter); - filter->SetInput(input); - filter->Update(); + mitk::Image::Pointer input; + mitk::Image::Pointer out; + if (inputImage->GetPixelType().GetTypeAsString() == "scalar (float)" || inputImage->GetPixelType().GetTypeAsString() == " (float)") + input = inputImage; + else + input = ApplyCropping(inputImage, 0, 0, 0, 0, 0, inputImage->GetDimension(2) - 1); + + if (!UseGPU) + { + PhotoacousticBModeFilter::Pointer filter = PhotoacousticBModeFilter::New(); + filter->SetParameters(UseLogFilter); + filter->SetInput(input); + filter->Update(); - auto out = filter->GetOutput(); + out = filter->GetOutput(); - if(resampleSpacing == 0) - return out; + if (resampleSpacing == 0) + return out; + } + #ifdef PHOTOACOUSTICS_USE_GPU + else + { + PhotoacousticOCLBModeFilter::Pointer filter = PhotoacousticOCLBModeFilter::New(); + filter->SetParameters(UseLogFilter); + filter->SetInput(input); + filter->Update(); + + out = filter->GetOutput(); + + if (resampleSpacing == 0) + return out; + } + #endif typedef itk::ResampleImageFilter < itkFloatImageType, itkFloatImageType > ResampleImageFilter; ResampleImageFilter::Pointer resampleImageFilter = ResampleImageFilter::New(); itkFloatImageType::Pointer itkImage; mitk::CastToItkImage(out, itkImage); itkFloatImageType::SpacingType outputSpacing; itkFloatImageType::SizeType inputSize = itkImage->GetLargestPossibleRegion().GetSize(); itkFloatImageType::SizeType outputSize = inputSize; outputSpacing[0] = itkImage->GetSpacing()[0]; outputSpacing[1] = resampleSpacing; outputSpacing[2] = itkImage->GetSpacing()[2]; outputSize[1] = inputSize[1] * itkImage->GetSpacing()[1] / outputSpacing[1]; typedef itk::IdentityTransform TransformType; resampleImageFilter->SetInput(itkImage); resampleImageFilter->SetSize(outputSize); resampleImageFilter->SetOutputSpacing(outputSpacing); resampleImageFilter->SetTransform(TransformType::New()); resampleImageFilter->UpdateLargestPossibleRegion(); return mitk::GrabItkImageMemory(resampleImageFilter->GetOutput()); } - else if (method == BModeMethod::ShapeDetection) + else if (method == BModeMethod::EnvelopeDetection) { typedef itk::BModeImageFilter < itkFloatImageType, itkFloatImageType > BModeFilterType; BModeFilterType::Pointer bModeFilter = BModeFilterType::New(); // LogFilter typedef itk::PhotoacousticBModeImageFilter < itkFloatImageType, itkFloatImageType > PhotoacousticBModeImageFilter; PhotoacousticBModeImageFilter::Pointer photoacousticBModeFilter = PhotoacousticBModeImageFilter::New(); // No LogFilter typedef itk::ResampleImageFilter < itkFloatImageType, itkFloatImageType > ResampleImageFilter; ResampleImageFilter::Pointer resampleImageFilter = ResampleImageFilter::New(); itkFloatImageType::Pointer itkImage; mitk::CastToItkImage(inputImage, itkImage); itkFloatImageType::Pointer bmode; if (UseLogFilter) { bModeFilter->SetInput(itkImage); bModeFilter->SetDirection(1); bmode = bModeFilter->GetOutput(); } else { photoacousticBModeFilter->SetInput(itkImage); photoacousticBModeFilter->SetDirection(1); bmode = photoacousticBModeFilter->GetOutput(); } // resampleSpacing == 0 means: do no resampling if (resampleSpacing == 0) { return mitk::GrabItkImageMemory(bmode); } itkFloatImageType::SpacingType outputSpacing; itkFloatImageType::SizeType inputSize = itkImage->GetLargestPossibleRegion().GetSize(); itkFloatImageType::SizeType outputSize = inputSize; outputSpacing[0] = itkImage->GetSpacing()[0]; outputSpacing[1] = resampleSpacing; outputSpacing[2] = itkImage->GetSpacing()[2]; outputSize[1] = inputSize[1] * itkImage->GetSpacing()[1] / outputSpacing[1]; resampleImageFilter->SetInput(bmode); resampleImageFilter->SetSize(outputSize); resampleImageFilter->SetOutputSpacing(outputSpacing); resampleImageFilter->SetTransform(TransformType::New()); resampleImageFilter->UpdateLargestPossibleRegion(); return mitk::GrabItkImageMemory(resampleImageFilter->GetOutput()); } return nullptr; } /*mitk::Image::Pointer mitk::PhotoacousticImage::ApplyScatteringCompensation(mitk::Image::Pointer inputImage, int scattering) { typedef itk::Image< float, 3 > itkFloatImageType; typedef itk::MultiplyImageFilter MultiplyImageFilterType; itkFloatImageType::Pointer itkImage; mitk::CastToItkImage(inputImage, itkImage); MultiplyImageFilterType::Pointer multiplyFilter = MultiplyImageFilterType::New(); multiplyFilter->SetInput1(itkImage); multiplyFilter->SetInput2(m_FluenceCompResizedItk.at(m_ScatteringCoefficient)); return mitk::GrabItkImageMemory(multiplyFilter->GetOutput()); }*/ mitk::Image::Pointer mitk::PhotoacousticImage::ApplyResampling(mitk::Image::Pointer inputImage, unsigned int outputSize[2]) { typedef itk::Image< float, 3 > itkFloatImageType; typedef itk::ResampleImageFilter < itkFloatImageType, itkFloatImageType > ResampleImageFilter; ResampleImageFilter::Pointer resampleImageFilter = ResampleImageFilter::New(); typedef itk::LinearInterpolateImageFunction T_Interpolator; itkFloatImageType::Pointer itkImage; mitk::CastToItkImage(inputImage, itkImage); itkFloatImageType::SpacingType outputSpacingItk; itkFloatImageType::SizeType inputSizeItk = itkImage->GetLargestPossibleRegion().GetSize(); itkFloatImageType::SizeType outputSizeItk = inputSizeItk; outputSizeItk[0] = outputSize[0]; outputSizeItk[1] = outputSize[1]; outputSizeItk[2] = inputSizeItk[2]; outputSpacingItk[0] = itkImage->GetSpacing()[0] * (static_cast(inputSizeItk[0]) / static_cast(outputSizeItk[0])); outputSpacingItk[1] = itkImage->GetSpacing()[1] * (static_cast(inputSizeItk[1]) / static_cast(outputSizeItk[1])); outputSpacingItk[2] = itkImage->GetSpacing()[2]; typedef itk::IdentityTransform TransformType; T_Interpolator::Pointer _pInterpolator = T_Interpolator::New(); resampleImageFilter->SetInput(itkImage); resampleImageFilter->SetSize(outputSizeItk); resampleImageFilter->SetOutputSpacing(outputSpacingItk); resampleImageFilter->SetTransform(TransformType::New()); resampleImageFilter->SetInterpolator(_pInterpolator); resampleImageFilter->UpdateLargestPossibleRegion(); return mitk::GrabItkImageMemory(resampleImageFilter->GetOutput()); } mitk::Image::Pointer mitk::PhotoacousticImage::ApplyCropping(mitk::Image::Pointer inputImage, int above, int below, int right, int left, int minSlice, int maxSlice) { unsigned int inputDim[3] = { inputImage->GetDimension(0), inputImage->GetDimension(1), inputImage->GetDimension(2) }; unsigned int outputDim[3] = { inputImage->GetDimension(0) - left - right, inputImage->GetDimension(1) - (unsigned int)above - (unsigned int)below, (unsigned int)maxSlice - (unsigned int)minSlice + 1 }; void* inputData; float* outputData = new float[outputDim[0] * outputDim[1] * outputDim[2]]; ImageReadAccessor acc(inputImage); inputData = const_cast(acc.GetData()); // convert the data to float by default - // as of now only those float, short, float are used at all... though it's easy to add other ones + // as of now only float, short, double are used at all. if (inputImage->GetPixelType().GetTypeAsString() == "scalar (float)" || inputImage->GetPixelType().GetTypeAsString() == " (float)") { // copy the data into the cropped image for (unsigned short sl = 0; sl < outputDim[2]; ++sl) { for (unsigned short l = 0; l < outputDim[0]; ++l) { for (unsigned short s = 0; s < outputDim[1]; ++s) { outputData[l + s*(unsigned short)outputDim[0] + sl*outputDim[0] * outputDim[1]] = (float)((float*)inputData)[(l + left) + (s + above)*(unsigned short)inputDim[0] + (sl + minSlice)*inputDim[0] * inputDim[1]]; } } } } else if (inputImage->GetPixelType().GetTypeAsString() == "scalar (short)" || inputImage->GetPixelType().GetTypeAsString() == " (short)") { - // copy the data unsigned shorto the cropped image + // copy the data to the cropped image for (unsigned short sl = 0; sl < outputDim[2]; ++sl) { for (unsigned short l = 0; l < outputDim[0]; ++l) { for (unsigned short s = 0; s < outputDim[1]; ++s) { outputData[l + s*(unsigned short)outputDim[0] + sl*outputDim[0] * outputDim[1]] = (float)((short*)inputData)[(l + left) + (s + above)*(unsigned short)inputDim[0] + (sl + minSlice)*inputDim[0] * inputDim[1]]; } } } } else if (inputImage->GetPixelType().GetTypeAsString() == "scalar (double)" || inputImage->GetPixelType().GetTypeAsString() == " (double)") { - // copy the data unsigned shorto the cropped image + // copy the data to the cropped image for (unsigned short sl = 0; sl < outputDim[2]; ++sl) { for (unsigned short l = 0; l < outputDim[0]; ++l) { for (unsigned short s = 0; s < outputDim[1]; ++s) { outputData[l + s*(unsigned short)outputDim[0] + sl*outputDim[0] * outputDim[1]] = (float)((double*)inputData)[(l + left) + (s + above)*(unsigned short)inputDim[0] + (sl + minSlice)*inputDim[0] * inputDim[1]]; } } } } else { MITK_INFO << "Could not determine pixel type"; } mitk::Image::Pointer output = mitk::Image::New(); output->Initialize(mitk::MakeScalarPixelType(), 3, outputDim); output->SetSpacing(inputImage->GetGeometry()->GetSpacing()); output->SetImportVolume(outputData, 0, 0, mitk::Image::ReferenceMemory); return output; } -mitk::Image::Pointer mitk::PhotoacousticImage::ApplyBeamforming(mitk::Image::Pointer inputImage, BeamformingFilter::beamformingSettings config, int cutoff, std::function progressHandle) +mitk::Image::Pointer mitk::PhotoacousticImage::ApplyBeamforming(mitk::Image::Pointer inputImage, BeamformingSettings config, std::string& message, std::function progressHandle) { - // crop the image - // set the Maximum Size of the image to 4096 - unsigned short lowerCutoff = 0; - if (((unsigned int)(4096 + cutoff)) < inputImage->GetDimension(1)) + Image::Pointer processedImage = inputImage; + if (inputImage->GetDimension() != 3) { - lowerCutoff = (unsigned short)(inputImage->GetDimension(1) - 4096); + processedImage->Initialize(mitk::MakeScalarPixelType(), 3, inputImage->GetDimensions()); + processedImage->SetSpacing(inputImage->GetGeometry()->GetSpacing()); + + mitk::ImageReadAccessor copy(inputImage); + + processedImage->SetImportVolume(copy.GetData()); } - config.RecordTime = config.RecordTime - (cutoff + lowerCutoff) / inputImage->GetDimension(1) * config.RecordTime; // adjust the recorded time lost by cropping - progressHandle(0, "cropping image"); + config.RecordTime = config.RecordTime - (float)(config.upperCutoff) / (float)inputImage->GetDimension(1) * config.RecordTime; // adjust the recorded time lost by cropping + progressHandle(0, "converting image"); if (!config.partial) { config.CropBounds[0] = 0; config.CropBounds[1] = inputImage->GetDimension(2) - 1; } + processedImage = ApplyCropping(inputImage, config.upperCutoff, 0, 0, 0, config.CropBounds[0], config.CropBounds[1]); - Image::Pointer processedImage = ApplyCropping(inputImage, cutoff, lowerCutoff, 0, 0, config.CropBounds[0], config.CropBounds[1]); - - // resample the image in horizontal direction - if (inputImage->GetDimension(0) != config.ReconstructionLines) - { - progressHandle(0, "resampling image"); - auto begin = std::chrono::high_resolution_clock::now(); - unsigned int dim[2] = { config.ReconstructionLines, processedImage->GetDimension(1) }; - processedImage = ApplyResampling(processedImage, dim); - auto end = std::chrono::high_resolution_clock::now(); - MITK_DEBUG << "Upsampling from " << inputImage->GetDimension(0) << " to " << config.ReconstructionLines << " lines completed in " << ((double)std::chrono::duration_cast(end - begin).count()) / 1000000 << "ms" << std::endl; - } + config.inputDim[0] = processedImage->GetDimension(0); + config.inputDim[1] = processedImage->GetDimension(1); + config.inputDim[2] = processedImage->GetDimension(2); // perform the beamforming - BeamformingFilter::Pointer Beamformer = BeamformingFilter::New(); - Beamformer->SetInput(processedImage); - Beamformer->Configure(config); - Beamformer->SetProgressHandle(progressHandle); - Beamformer->UpdateLargestPossibleRegion(); + m_BeamformingFilter->SetInput(processedImage); + m_BeamformingFilter->Configure(config); + m_BeamformingFilter->SetProgressHandle(progressHandle); + m_BeamformingFilter->UpdateLargestPossibleRegion(); - processedImage = Beamformer->GetOutput(); + processedImage = m_BeamformingFilter->GetOutput(); + message = m_BeamformingFilter->GetMessageString(); return processedImage; } mitk::Image::Pointer mitk::PhotoacousticImage::BandpassFilter(mitk::Image::Pointer data, float recordTime, float BPHighPass, float BPLowPass, float alpha) { bool powerOfTwo = false; int finalPower = 0; for (int i = 1; pow(2, i) <= data->GetDimension(1); ++i) { finalPower = i; if (pow(2, i) == data->GetDimension(1)) { powerOfTwo = true; } } if (!powerOfTwo) { unsigned int dim[2] = { data->GetDimension(0), (unsigned int)pow(2,finalPower+1)}; data = ApplyResampling(data, dim); } MITK_INFO << data->GetDimension(0); // do a fourier transform, multiply with an appropriate window for the filter, and transform back typedef float PixelType; typedef itk::Image< PixelType, 3 > RealImageType; RealImageType::Pointer image; mitk::CastToItkImage(data, image); typedef itk::FFT1DRealToComplexConjugateImageFilter ForwardFFTFilterType; typedef ForwardFFTFilterType::OutputImageType ComplexImageType; ForwardFFTFilterType::Pointer forwardFFTFilter = ForwardFFTFilterType::New(); forwardFFTFilter->SetInput(image); forwardFFTFilter->SetDirection(1); try { forwardFFTFilter->UpdateOutputInformation(); } catch (itk::ExceptionObject & error) { std::cerr << "Error: " << error << std::endl; MITK_WARN << "Bandpass could not be applied"; return data; } float singleVoxel = 1 / (recordTime / data->GetDimension(1)) / 2 / 1000; float cutoffPixelHighPass = std::min(BPHighPass / singleVoxel, (float)data->GetDimension(1) / 2); float cutoffPixelLowPass = std::min(BPLowPass / singleVoxel, (float)data->GetDimension(1) / 2 - cutoffPixelHighPass); RealImageType::Pointer fftMultiplicator = BPFunction(data, cutoffPixelHighPass, cutoffPixelLowPass, alpha); typedef itk::MultiplyImageFilter< ComplexImageType, RealImageType, ComplexImageType > MultiplyFilterType; MultiplyFilterType::Pointer multiplyFilter = MultiplyFilterType::New(); multiplyFilter->SetInput1(forwardFFTFilter->GetOutput()); multiplyFilter->SetInput2(fftMultiplicator); /*itk::ComplexToModulusImageFilter::Pointer toReal = itk::ComplexToModulusImageFilter::New(); toReal->SetInput(forwardFFTFilter->GetOutput()); return GrabItkImageMemory(toReal->GetOutput()); return GrabItkImageMemory(fftMultiplicator); *///DEBUG typedef itk::FFT1DComplexConjugateToRealImageFilter< ComplexImageType, RealImageType > InverseFilterType; InverseFilterType::Pointer inverseFFTFilter = InverseFilterType::New(); inverseFFTFilter->SetInput(multiplyFilter->GetOutput()); inverseFFTFilter->SetDirection(1); return GrabItkImageMemory(inverseFFTFilter->GetOutput()); } itk::Image::Pointer mitk::PhotoacousticImage::BPFunction(mitk::Image::Pointer reference, int cutoffFrequencyPixelHighPass, int cutoffFrequencyPixelLowPass, float alpha) { float* imageData = new float[reference->GetDimension(0)*reference->GetDimension(1)]; // tukey window float width = reference->GetDimension(1) / 2 - (float)cutoffFrequencyPixelHighPass - (float)cutoffFrequencyPixelLowPass; float center = (float)cutoffFrequencyPixelHighPass / 2 + width / 2; MITK_INFO << width << "width " << center << "center " << alpha; for (unsigned int n = 0; n < reference->GetDimension(1); ++n) { imageData[reference->GetDimension(0)*n] = 0; } - - for (int n = 0; n < width; ++n) + if (alpha < 0.00001) { - if (n <= (alpha*(width - 1)) / 2) - { - imageData[reference->GetDimension(0)*(int)(n + center - (width / 2))] = (1 + cos(M_PI*(2 * n / (alpha*(width - 1)) - 1))) / 2; - } - else if (n >= (width - 1)*(1 - alpha / 2) && n <= (width - 1)) + for (int n = 0; n < width; ++n) { - imageData[reference->GetDimension(0)*(int)(n + center - (width / 2))] = (1 + cos(M_PI*(2 * n / (alpha*(width - 1)) + 1 - 2 / alpha))) / 2; + if (n <= (alpha*(width - 1)) / 2) + { + imageData[reference->GetDimension(0)*(int)(n + center - (width / 2))] = (1 + cos(M_PI*(2 * n / (alpha*(width - 1)) - 1))) / 2; + } + else if (n >= (width - 1)*(1 - alpha / 2)) + { + imageData[reference->GetDimension(0)*(int)(n + center - (width / 2))] = (1 + cos(M_PI*(2 * n / (alpha*(width - 1)) + 1 - 2 / alpha))) / 2; + } + else + { + imageData[reference->GetDimension(0)*(int)(n + center - (width / 2))] = 1; + } } - else + } + else + { + for (int n = 0; n < width; ++n) { imageData[reference->GetDimension(0)*(int)(n + center - (width / 2))] = 1; } } - // Butterworth-Filter /* // first, write the HighPass if (cutoffFrequencyPixelHighPass != reference->GetDimension(1) / 2) { for (int n = 0; n < reference->GetDimension(1) / 2; ++n) { imageData[reference->GetDimension(0)*n] = 1 / (1 + pow( (float)n / (float)(reference->GetDimension(1) / 2 - cutoffFrequencyPixelHighPass) , 2 * butterworthOrder)); } } else { for (int n = 0; n < reference->GetDimension(1) / 2; ++n) { imageData[reference->GetDimension(0)*n] = 1; } } // now, the LowPass for (int n = 0; n < reference->GetDimension(1) / 2; ++n) { imageData[reference->GetDimension(0)*n] *= 1 / (1 + pow( (float)(reference->GetDimension(1) / 2 - 1 - n) / (float)(reference->GetDimension(1) / 2 - cutoffFrequencyPixelLowPass) , 2 * butterworthOrder)); } */ // mirror the first half of the image for (unsigned int n = reference->GetDimension(1) / 2; n < reference->GetDimension(1); ++n) { imageData[reference->GetDimension(0)*n] = imageData[(reference->GetDimension(1) - (n + 1)) * reference->GetDimension(0)]; } // copy and paste to all lines for (unsigned int line = 1; line < reference->GetDimension(0); ++line) { for (unsigned int sample = 0; sample < reference->GetDimension(1); ++sample) { imageData[reference->GetDimension(0)*sample + line] = imageData[reference->GetDimension(0)*sample]; } } typedef itk::Image< float, 3U > ImageType; ImageType::RegionType region; ImageType::IndexType start; start.Fill(0); region.SetIndex(start); ImageType::SizeType size; size[0] = reference->GetDimension(0); size[1] = reference->GetDimension(1); size[2] = reference->GetDimension(2); region.SetSize(size); ImageType::SpacingType SpacingItk; SpacingItk[0] = reference->GetGeometry()->GetSpacing()[0]; SpacingItk[1] = reference->GetGeometry()->GetSpacing()[1]; SpacingItk[2] = reference->GetGeometry()->GetSpacing()[2]; ImageType::Pointer image = ImageType::New(); image->SetRegions(region); image->Allocate(); image->FillBuffer(itk::NumericTraits::Zero); image->SetSpacing(SpacingItk); ImageType::IndexType pixelIndex; for (ImageType::IndexValueType slice = 0; slice < reference->GetDimension(2); ++slice) { for (ImageType::IndexValueType line = 0; line < reference->GetDimension(0); ++line) { for (ImageType::IndexValueType sample = 0; sample < reference->GetDimension(1); ++sample) { pixelIndex[0] = line; pixelIndex[1] = sample; pixelIndex[2] = slice; image->SetPixel(pixelIndex, imageData[line + sample*reference->GetDimension(0)]); } } } delete[] imageData; return image; } - - -/* -mitk::CropFilter::CropFilter() - : m_PixelCalculation(NULL) -{ - this->AddSourceFile("CropFilter.cl"); - - this->m_FilterID = "CropFilter"; -} - -mitk::CropFilter::~CropFilter() -{ - if (this->m_PixelCalculation) - { - clReleaseKernel(m_PixelCalculation); - } -} - -void mitk::CropFilter::Update() -{ - //Check if context & program available - if (!this->Initialize()) - { - us::ServiceReference ref = GetModuleContext()->GetServiceReference(); - OclResourceService* resources = GetModuleContext()->GetService(ref); - - // clean-up also the resources - resources->InvalidateStorage(); - mitkThrow() << "Filter is not initialized. Cannot update."; - } - else { - // Execute - this->Execute(); - } -} - -void mitk::CropFilter::Execute() -{ - cl_int clErr = 0; - - try - { - this->InitExec(this->m_PixelCalculation); - } - catch (const mitk::Exception& e) - { - MITK_ERROR << "Catched exception while initializing filter: " << e.what(); - return; - } - - us::ServiceReference ref = GetModuleContext()->GetServiceReference(); - OclResourceService* resources = GetModuleContext()->GetService(ref); - cl_context gpuContext = resources->GetContext(); - - unsigned int size = m_OutputDim[0] * m_OutputDim[1] * m_OutputDim[2] * m_Images; - - cl_mem cl_input = clCreateBuffer(gpuContext, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, sizeof(float) * size, m_Data, &clErr); - CHECK_OCL_ERR(clErr); - - // set kernel arguments - clErr = clSetKernelArg(this->m_PixelCalculation, 2, sizeof(cl_mem), &cl_input); - clErr |= clSetKernelArg(this->m_PixelCalculation, 3, sizeof(cl_ushort), &(this->m_Images)); - - CHECK_OCL_ERR(clErr); - - // execute the filter on a 3D NDRange - this->ExecuteKernel(m_PixelCalculation, 3); - - // signalize the GPU-side data changed - m_Output->Modified(GPU_DATA); -} - -us::Module *mitk::CropFilter::GetModule() -{ - return us::GetModuleContext()->GetModule(); -} - -bool mitk::CropFilter::Initialize() -{ - bool buildErr = true; - cl_int clErr = 0; - - if (OclFilter::Initialize()) - { - this->m_PixelCalculation = clCreateKernel(this->m_ClProgram, "ckCrop", &clErr); - buildErr |= CHECK_OCL_ERR(clErr); - } - return (OclFilter::IsInitialized() && buildErr); -} - -void mitk::CropFilter::SetInput(mitk::Image::Pointer image) -{ - if (image->GetDimension() != 3) - { - mitkThrowException(mitk::Exception) << "Input for " << this->GetNameOfClass() << - " is not 3D. The filter only supports 3D. Please change your input."; - } - OclImageToImageFilter::SetInput(image); -} - -mitk::Image::Pointer mitk::CropFilter::GetOutput() -{ - if (m_Output->IsModified(GPU_DATA)) - { - void* pData = m_Output->TransferDataToCPU(m_CommandQue); - - const unsigned int dimension = 3; - unsigned int* dimensions = m_OutputDim; - - const mitk::SlicedGeometry3D::Pointer p_slg = m_Input->GetMITKImage()->GetSlicedGeometry(); - - MITK_DEBUG << "Creating new MITK Image."; - - m_Output->GetMITKImage()->Initialize(this->GetOutputType(), dimension, dimensions); - m_Output->GetMITKImage()->SetSpacing(p_slg->GetSpacing()); - m_Output->GetMITKImage()->SetGeometry(m_Input->GetMITKImage()->GetGeometry()); - m_Output->GetMITKImage()->SetImportVolume(pData, 0, 0, mitk::Image::ReferenceMemory); - } - - MITK_DEBUG << "Image Initialized."; - - return m_Output->GetMITKImage(); -} - -*/ diff --git a/Plugins/PluginList.cmake b/Plugins/PluginList.cmake index 6f48963d63..289676cd0e 100644 --- a/Plugins/PluginList.cmake +++ b/Plugins/PluginList.cmake @@ -1,104 +1,105 @@ # 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.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.cest:OFF org.mitk.gui.qt.exampleplugin:OFF org.mitk.gui.qt.surfaceregistration:OFF org.mitk.gui.qt.shapecomparison:OFF org.mitk.gui.qt.shapemodelutil:OFF ) diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/manifest_headers.cmake b/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/manifest_headers.cmake index 5b0e19249f..95d38debb1 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/manifest_headers.cmake +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/manifest_headers.cmake @@ -1,5 +1,5 @@ set(Plugin-Name "MITK Connectomics") set(Plugin-Version "1.0.0") set(Plugin-Vendor "DKFZ, Medical and Biological Informatics") set(Plugin-ContactAddress "http://www.mitk.org") -set(Require-Plugin org.mitk.gui.qt.diffusionimaging org.mitk.gui.qt.common.legacy org.mitk.gui.qt.common) +set(Require-Plugin org.mitk.gui.qt.diffusionimaging org.mitk.gui.qt.common) diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.denoising/manifest_headers.cmake b/Plugins/org.mitk.gui.qt.diffusionimaging.denoising/manifest_headers.cmake index ccf353c8c9..cd38bf46fc 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.denoising/manifest_headers.cmake +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.denoising/manifest_headers.cmake @@ -1,5 +1,5 @@ set(Plugin-Name "MITK DWI Denoising") set(Plugin-Version "1.0.0") set(Plugin-Vendor "DKFZ, Medical and Biological Informatics") set(Plugin-ContactAddress "http://www.mitk.org") -set(Require-Plugin org.mitk.gui.qt.diffusionimaging org.mitk.gui.qt.common.legacy org.mitk.gui.qt.common) +set(Require-Plugin org.mitk.gui.qt.diffusionimaging org.mitk.gui.qt.common) diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/manifest_headers.cmake b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/manifest_headers.cmake index 2e376675b7..75fc472cfc 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/manifest_headers.cmake +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/manifest_headers.cmake @@ -1,5 +1,5 @@ set(Plugin-Name "MITK Fiberfox") set(Plugin-Version "1.0.0") set(Plugin-Vendor "DKFZ, Medical and Biological Informatics") set(Plugin-ContactAddress "http://www.mitk.org") -set(Require-Plugin org.mitk.gui.qt.diffusionimaging org.mitk.gui.qt.common.legacy org.mitk.gui.qt.common) +set(Require-Plugin org.mitk.gui.qt.diffusionimaging org.mitk.gui.qt.common) diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/manifest_headers.cmake b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/manifest_headers.cmake index 074d5c67ef..2f6a8b321e 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/manifest_headers.cmake +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/manifest_headers.cmake @@ -1,5 +1,5 @@ set(Plugin-Name "MITK Fiber Processing") set(Plugin-Version "1.0.0") set(Plugin-Vendor "DKFZ, Medical and Biological Informatics") set(Plugin-ContactAddress "http://www.mitk.org") -set(Require-Plugin org.mitk.gui.qt.diffusionimaging org.mitk.gui.qt.common.legacy org.mitk.gui.qt.common) +set(Require-Plugin org.mitk.gui.qt.diffusionimaging org.mitk.gui.qt.common) diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/manifest_headers.cmake b/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/manifest_headers.cmake index c410e854d2..3385c26aaf 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/manifest_headers.cmake +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/manifest_headers.cmake @@ -1,5 +1,5 @@ set(Plugin-Name "MITK IVIM") set(Plugin-Version "1.0.0") set(Plugin-Vendor "DKFZ, Medical and Biological Informatics") set(Plugin-ContactAddress "http://www.mitk.org") -set(Require-Plugin org.mitk.gui.qt.diffusionimaging org.mitk.gui.qt.common.legacy org.mitk.gui.qt.common) +set(Require-Plugin org.mitk.gui.qt.diffusionimaging org.mitk.gui.qt.common) diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.odfpeaks/manifest_headers.cmake b/Plugins/org.mitk.gui.qt.diffusionimaging.odfpeaks/manifest_headers.cmake index d9d2df538c..01c8d1dc61 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.odfpeaks/manifest_headers.cmake +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.odfpeaks/manifest_headers.cmake @@ -1,5 +1,5 @@ set(Plugin-Name "MITK ODF Peaks") set(Plugin-Version "1.0.0") set(Plugin-Vendor "DKFZ, Medical and Biological Informatics") set(Plugin-ContactAddress "http://www.mitk.org") -set(Require-Plugin org.mitk.gui.qt.diffusionimaging org.mitk.gui.qt.common.legacy org.mitk.gui.qt.common) +set(Require-Plugin org.mitk.gui.qt.diffusionimaging org.mitk.gui.qt.common) diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.partialvolume/manifest_headers.cmake b/Plugins/org.mitk.gui.qt.diffusionimaging.partialvolume/manifest_headers.cmake index dbf79c0d1e..a7e7171515 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.partialvolume/manifest_headers.cmake +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.partialvolume/manifest_headers.cmake @@ -1,5 +1,5 @@ set(Plugin-Name "MITK Partial Volume Analysis") set(Plugin-Version "1.0.0") set(Plugin-Vendor "DKFZ, Medical and Biological Informatics") set(Plugin-ContactAddress "http://www.mitk.org") -set(Require-Plugin org.mitk.gui.qt.diffusionimaging org.mitk.gui.qt.common.legacy org.mitk.gui.qt.common) +set(Require-Plugin org.mitk.gui.qt.diffusionimaging org.mitk.gui.qt.common) diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/CMakeLists.txt b/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/CMakeLists.txt index b80f3e0fb3..bcbe770470 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/CMakeLists.txt +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/CMakeLists.txt @@ -1,14 +1,10 @@ -if(MITK_USE_Python) - # The project name must correspond to the directory name of your plug-in # and must not contain periods. project(org_mitk_gui_qt_diffusionimaging_preprocessing) mitk_create_plugin( EXPORT_DIRECTIVE DIFFUSIONIMAGING_PREPROCESSING_EXPORT EXPORTED_INCLUDE_SUFFIXES src - MODULE_DEPENDS MitkDiffusionCore MitkPython MitkQtPython + MODULE_DEPENDS MitkDiffusionCore PACKAGE_DEPENDS Qt5|Network ) - -endif() diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/files.cmake b/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/files.cmake index 61c991d6e5..0009a93c61 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/files.cmake +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/files.cmake @@ -1,45 +1,42 @@ set(SRC_CPP_FILES ) set(INTERNAL_CPP_FILES mitkPluginActivator.cpp QmitkPreprocessingView.cpp - QmitkBrainExtractionView.cpp ) set(UI_FILES src/internal/QmitkPreprocessingViewControls.ui - src/internal/QmitkBrainExtractionViewControls.ui ) set(MOC_H_FILES src/internal/mitkPluginActivator.h src/internal/QmitkPreprocessingView.h - src/internal/QmitkBrainExtractionView.h ) set(CACHED_RESOURCE_FILES plugin.xml resources/preprocessing.png resources/dwi2.png ) 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.diffusionimaging.preprocessing/manifest_headers.cmake b/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/manifest_headers.cmake index b9885bba96..223766b673 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/manifest_headers.cmake +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/manifest_headers.cmake @@ -1,5 +1,5 @@ set(Plugin-Name "MITK Preprocessing") set(Plugin-Version "1.0.0") set(Plugin-Vendor "DKFZ, Medical and Biological Informatics") set(Plugin-ContactAddress "http://www.mitk.org") -set(Require-Plugin org.mitk.gui.qt.diffusionimaging org.mitk.gui.qt.common.legacy org.mitk.gui.qt.common) +set(Require-Plugin org.mitk.gui.qt.diffusionimaging org.mitk.gui.qt.common) diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/plugin.xml b/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/plugin.xml index c441b6d060..6fe5a3812b 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/plugin.xml +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/plugin.xml @@ -1,25 +1,17 @@ - - - - diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/mitkPluginActivator.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/mitkPluginActivator.cpp index aafe6330b1..baf96673ff 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/mitkPluginActivator.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/mitkPluginActivator.cpp @@ -1,44 +1,42 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkPluginActivator.h" #include "src/internal/QmitkPreprocessingView.h" -#include "src/internal/QmitkBrainExtractionView.h" #include ctkPluginContext* mitk::PluginActivator::m_Context = nullptr; US_INITIALIZE_MODULE ctkPluginContext* mitk::PluginActivator::GetContext() { return m_Context; } void mitk::PluginActivator::start(ctkPluginContext* context) { BERRY_REGISTER_EXTENSION_CLASS(QmitkPreprocessingView, context) - BERRY_REGISTER_EXTENSION_CLASS(QmitkBrainExtractionView, context) m_Context = context; } void mitk::PluginActivator::stop(ctkPluginContext* context) { Q_UNUSED(context) m_Context = nullptr; } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/CMakeLists.txt b/Plugins/org.mitk.gui.qt.diffusionimaging.python/CMakeLists.txt similarity index 85% copy from Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/CMakeLists.txt copy to Plugins/org.mitk.gui.qt.diffusionimaging.python/CMakeLists.txt index b80f3e0fb3..a0feafa1d4 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/CMakeLists.txt +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.python/CMakeLists.txt @@ -1,14 +1,14 @@ if(MITK_USE_Python) # The project name must correspond to the directory name of your plug-in # and must not contain periods. -project(org_mitk_gui_qt_diffusionimaging_preprocessing) +project(org_mitk_gui_qt_diffusionimaging_python) mitk_create_plugin( EXPORT_DIRECTIVE DIFFUSIONIMAGING_PREPROCESSING_EXPORT EXPORTED_INCLUDE_SUFFIXES src MODULE_DEPENDS MitkDiffusionCore MitkPython MitkQtPython PACKAGE_DEPENDS Qt5|Network ) endif() diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.python/documentation/doxygen/modules.dox b/Plugins/org.mitk.gui.qt.diffusionimaging.python/documentation/doxygen/modules.dox new file mode 100644 index 0000000000..c0a9180de7 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.python/documentation/doxygen/modules.dox @@ -0,0 +1,16 @@ +/** + \defgroup org_mitk_gui_qt_diffusionimaging_preprocessing org.mitk.gui.qt.diffusionimaging.preprocessing + \ingroup MITKPlugins + + \brief This is the diffusionimaging.preprocessing plugin. + +*/ + +/** + \defgroup org_mitk_gui_qt_diffusionimaging_preprocessing_internal Internal + \ingroup org_mitk_gui_qt_diffusionimaging_preprocessing + + \brief This subcategory includes the internal classes of the org.mitk.gui.qt.diffusionimaging.preprocessing plugin. Other + plugins must not rely on these classes. They contain implementation details and their interface + may change at any time. We mean it. +*/ diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/files.cmake b/Plugins/org.mitk.gui.qt.diffusionimaging.python/files.cmake similarity index 84% copy from Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/files.cmake copy to Plugins/org.mitk.gui.qt.diffusionimaging.python/files.cmake index 61c991d6e5..03078b8ef2 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/files.cmake +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.python/files.cmake @@ -1,45 +1,42 @@ set(SRC_CPP_FILES ) set(INTERNAL_CPP_FILES mitkPluginActivator.cpp - QmitkPreprocessingView.cpp QmitkBrainExtractionView.cpp ) set(UI_FILES - src/internal/QmitkPreprocessingViewControls.ui src/internal/QmitkBrainExtractionViewControls.ui ) set(MOC_H_FILES src/internal/mitkPluginActivator.h - src/internal/QmitkPreprocessingView.h src/internal/QmitkBrainExtractionView.h ) set(CACHED_RESOURCE_FILES plugin.xml resources/preprocessing.png resources/dwi2.png ) 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.diffusionimaging.preprocessing/manifest_headers.cmake b/Plugins/org.mitk.gui.qt.diffusionimaging.python/manifest_headers.cmake similarity index 85% copy from Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/manifest_headers.cmake copy to Plugins/org.mitk.gui.qt.diffusionimaging.python/manifest_headers.cmake index b9885bba96..223766b673 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/manifest_headers.cmake +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.python/manifest_headers.cmake @@ -1,5 +1,5 @@ set(Plugin-Name "MITK Preprocessing") set(Plugin-Version "1.0.0") set(Plugin-Vendor "DKFZ, Medical and Biological Informatics") set(Plugin-ContactAddress "http://www.mitk.org") -set(Require-Plugin org.mitk.gui.qt.diffusionimaging org.mitk.gui.qt.common.legacy org.mitk.gui.qt.common) +set(Require-Plugin org.mitk.gui.qt.diffusionimaging org.mitk.gui.qt.common) diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/plugin.xml b/Plugins/org.mitk.gui.qt.diffusionimaging.python/plugin.xml similarity index 60% copy from Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/plugin.xml copy to Plugins/org.mitk.gui.qt.diffusionimaging.python/plugin.xml index c441b6d060..69d3bf2441 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/plugin.xml +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.python/plugin.xml @@ -1,25 +1,17 @@ - - - - diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.python/resources/dwi2.png b/Plugins/org.mitk.gui.qt.diffusionimaging.python/resources/dwi2.png new file mode 100644 index 0000000000..c2087367ce Binary files /dev/null and b/Plugins/org.mitk.gui.qt.diffusionimaging.python/resources/dwi2.png differ diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.python/resources/preprocessing.png b/Plugins/org.mitk.gui.qt.diffusionimaging.python/resources/preprocessing.png new file mode 100644 index 0000000000..d7564ca333 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.diffusionimaging.python/resources/preprocessing.png differ diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.python/resources/preprocessing.xcf b/Plugins/org.mitk.gui.qt.diffusionimaging.python/resources/preprocessing.xcf new file mode 100644 index 0000000000..c7b840caf9 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.diffusionimaging.python/resources/preprocessing.xcf differ diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/QmitkBrainExtractionView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.python/src/internal/QmitkBrainExtractionView.cpp similarity index 80% rename from Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/QmitkBrainExtractionView.cpp rename to Plugins/org.mitk.gui.qt.diffusionimaging.python/src/internal/QmitkBrainExtractionView.cpp index 0f3b2340ac..a0f5da805b 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/QmitkBrainExtractionView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.python/src/internal/QmitkBrainExtractionView.cpp @@ -1,203 +1,229 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ //misc #define _USE_MATH_DEFINES #include // Blueberry #include #include // Qmitk #include "QmitkBrainExtractionView.h" // MITK #include // Qt #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include #define _USE_MATH_DEFINES #include FileDownloader::FileDownloader(QObject *parent) : QObject(parent) { } void FileDownloader::download(QUrl url) { connect(&m_WebCtrl, SIGNAL (finished(QNetworkReply*)), SLOT (Downloaded(QNetworkReply*))); QNetworkRequest request(url); m_WebCtrl.get(request); } void FileDownloader::Downloaded(QNetworkReply *reply) { MITK_INFO << "FileDownloader::Downloaded TESTTEST"; QFile localFile("/home/neher/test_download.tar.gz"); if (!localFile.open(QIODevice::WriteOnly)) return; localFile.write(reply->readAll()); localFile.close(); delete reply; QMessageBox::information(nullptr, "FILE DOWNLOADED", "BLABL"); } FileDownloader::~FileDownloader() { } const std::string QmitkBrainExtractionView::VIEW_ID = "org.mitk.views.brainextraction"; QmitkBrainExtractionView::QmitkBrainExtractionView() : QmitkAbstractView() , m_Controls( 0 ) , m_DiffusionImage( nullptr ) { } // Destructor QmitkBrainExtractionView::~QmitkBrainExtractionView() { } void QmitkBrainExtractionView::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::QmitkBrainExtractionViewControls; m_Controls->setupUi( parent ); connect( m_Controls->m_ImageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGUI()) ); connect( m_Controls->m_StartButton, SIGNAL(clicked()), this, SLOT(StartBrainExtraction()) ); this->m_Parent = parent; m_Controls->m_ImageBox->SetDataStorage(this->GetDataStorage()); mitk::NodePredicateDimension::Pointer dimPred = mitk::NodePredicateDimension::New(3); mitk::TNodePredicateDataType::Pointer isImagePredicate = mitk::TNodePredicateDataType::New(); - m_Controls->m_ImageBox->SetPredicate(mitk::NodePredicateAnd::New(isImagePredicate,dimPred)); +// m_Controls->m_ImageBox->SetPredicate(mitk::NodePredicateAnd::New(isImagePredicate,dimPred)); + m_Controls->m_ImageBox->SetPredicate(isImagePredicate); UpdateGUI(); std::string module_library_full_path = us::GetModuleContext()->GetModule()->GetLocation(); std::string library_file; itksys::SystemTools::SplitProgramPath(module_library_full_path, m_ModulePath, library_file); + m_ModulePath += "/BET"; } } void QmitkBrainExtractionView::OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList& ) { } void QmitkBrainExtractionView::UpdateGUI() { if (m_Controls->m_ImageBox->GetSelectedNode().IsNotNull()) m_Controls->m_StartButton->setEnabled(true); else m_Controls->m_StartButton->setEnabled(false); } void QmitkBrainExtractionView::SetFocus() { UpdateGUI(); m_Controls->m_StartButton->setFocus(); } void QmitkBrainExtractionView::StartBrainExtraction() { // FileDownloader dl; // dl.download(QUrl("http://mitk.org/download/releases/MITK-2012.06/MITK-2012.06.0-src.tar.gz")); mitk::DataNode::Pointer node = m_Controls->m_ImageBox->GetSelectedNode(); mitk::Image::Pointer mitk_image = dynamic_cast(node->GetData()); + bool missing_file = false; + std::string missing_file_string = ""; if ( !itksys::SystemTools::FileExists(m_ModulePath + "/brain_extraction_script.py") ) { - QMessageBox::warning(nullptr, "Error", ("Brain extraction script file missing:\n" + m_ModulePath + "/brain_extraction_script.py").c_str(), QMessageBox::Ok); - return; + missing_file_string += "Brain extraction script file missing:\n" + m_ModulePath + "/brain_extraction_script.py\n\n"; + missing_file = true; } if ( !itksys::SystemTools::FileExists(m_ModulePath + "/brain_extraction_model.model") ) { - QMessageBox::warning(nullptr, "Error", ("Brain extraction model file missing:\n" + m_ModulePath + "/brain_extraction_model.model").c_str(), QMessageBox::Ok); + missing_file_string += "Brain extraction model file missing:\n" + m_ModulePath + "/brain_extraction_model.model\n\n"; + missing_file = true; + } + + if ( !itksys::SystemTools::FileExists(m_ModulePath + "/basic_config_just_like_braintumor.py") ) + { + missing_file_string += "Config file missing:\n" + m_ModulePath + "/basic_config_just_like_braintumor.py\n\n"; + missing_file = true; + } + + if (missing_file) + { + QMessageBox::warning(nullptr, "Error", (missing_file_string).c_str(), QMessageBox::Ok); return; } try { us::ModuleContext* context = us::GetModuleContext(); us::ServiceReference m_PythonServiceRef = context->GetServiceReference(); mitk::IPythonService* m_PythonService = dynamic_cast ( context->GetService(m_PythonServiceRef) ); mitk::IPythonService::ForceLoadModule(); m_PythonService->Execute("import SimpleITK as sitk"); m_PythonService->Execute("import SimpleITK._SimpleITK as _SimpleITK"); m_PythonService->Execute("import numpy"); m_PythonService->CopyToPythonAsSimpleItkImage( mitk_image, "in_image"); - m_PythonService->Execute("model=\""+m_ModulePath+"/brain_extraction_model.model\""); + m_PythonService->Execute("model_file=\""+m_ModulePath+"/brain_extraction_model.model\""); + m_PythonService->Execute("config_file=\""+m_ModulePath+"/basic_config_just_like_braintumor.py\""); m_PythonService->ExecuteScript(m_ModulePath + "/brain_extraction_script.py"); { mitk::Image::Pointer image = m_PythonService->CopySimpleItkImageFromPython("brain_mask"); mitk::DataNode::Pointer corrected_node = mitk::DataNode::New(); corrected_node->SetData( image ); QString name(node->GetName().c_str()); name += "_BrainMask"; corrected_node->SetName(name.toStdString()); GetDataStorage()->Add(corrected_node, node); } { mitk::Image::Pointer image = m_PythonService->CopySimpleItkImageFromPython("brain_extracted"); + + if(mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(mitk_image)) + { + mitk::DiffusionPropertyHelper propertyHelper(image); + mitk::DiffusionPropertyHelper::CopyProperties(mitk_image, image, true); + propertyHelper.InitializeImage(); + } + mitk::DataNode::Pointer corrected_node = mitk::DataNode::New(); corrected_node->SetData( image ); QString name(node->GetName().c_str()); name += "_SkullStripped"; corrected_node->SetName(name.toStdString()); GetDataStorage()->Add(corrected_node, node); } } catch(...) { QMessageBox::warning(nullptr, "Error", "File could not be processed.\nIs pytorch installed on your system?\nDoes your script use the correct input and output variable names (in: in_image & model, out: brain_mask & brain_extracted)?", QMessageBox::Ok); } } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/QmitkBrainExtractionView.h b/Plugins/org.mitk.gui.qt.diffusionimaging.python/src/internal/QmitkBrainExtractionView.h similarity index 94% rename from Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/QmitkBrainExtractionView.h rename to Plugins/org.mitk.gui.qt.diffusionimaging.python/src/internal/QmitkBrainExtractionView.h index cab1e08a64..6ffc91add7 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/QmitkBrainExtractionView.h +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.python/src/internal/QmitkBrainExtractionView.h @@ -1,100 +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. ===================================================================*/ #include #include #include #include "ui_QmitkBrainExtractionViewControls.h" #include #include #include #include #include #include #include +#include class QmitkBrainExtractionView; class FileDownloader : public QObject { Q_OBJECT public: explicit FileDownloader(QObject *parent = 0); virtual ~FileDownloader(); QByteArray downloadedData() const; void download(QUrl url); protected slots: void Downloaded(QNetworkReply* reply); private: QNetworkAccessManager m_WebCtrl; }; /*! \brief View for diffusion image registration / head motion correction */ class QmitkBrainExtractionView : public QmitkAbstractView { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: static const std::string VIEW_ID; + typedef itk::VectorImage< short, 3 > ItkDwiType; + typedef mitk::GradientDirectionsProperty GradProp; + QmitkBrainExtractionView(); virtual ~QmitkBrainExtractionView(); virtual void CreateQtPartControl(QWidget *parent) override; void SetFocus() override; protected slots: void StartBrainExtraction(); void UpdateGUI(); ///< update button activity etc. dpending on current datamanager selection protected: /// \brief called by QmitkAbstractView when DataManager's selection has changed virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList& nodes) override; Ui::QmitkBrainExtractionViewControls* m_Controls; mitk::Image::Pointer m_DiffusionImage; std::vector< mitk::DataNode::Pointer > m_SelectedDiffusionNodes; private: void UpdateRegistrationStatus(); ///< update textual status display of the Registration process // the Qt parent of our GUI (NOT of this object) QWidget* m_Parent; std::string m_ModulePath; }; diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/QmitkBrainExtractionViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.python/src/internal/QmitkBrainExtractionViewControls.ui similarity index 100% rename from Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/QmitkBrainExtractionViewControls.ui rename to Plugins/org.mitk.gui.qt.diffusionimaging.python/src/internal/QmitkBrainExtractionViewControls.ui diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/mitkPluginActivator.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.python/src/internal/mitkPluginActivator.cpp similarity index 90% copy from Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/mitkPluginActivator.cpp copy to Plugins/org.mitk.gui.qt.diffusionimaging.python/src/internal/mitkPluginActivator.cpp index aafe6330b1..c7d80cff99 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/mitkPluginActivator.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.python/src/internal/mitkPluginActivator.cpp @@ -1,44 +1,42 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkPluginActivator.h" -#include "src/internal/QmitkPreprocessingView.h" #include "src/internal/QmitkBrainExtractionView.h" #include ctkPluginContext* mitk::PluginActivator::m_Context = nullptr; US_INITIALIZE_MODULE ctkPluginContext* mitk::PluginActivator::GetContext() { return m_Context; } void mitk::PluginActivator::start(ctkPluginContext* context) { - BERRY_REGISTER_EXTENSION_CLASS(QmitkPreprocessingView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkBrainExtractionView, context) m_Context = context; } void mitk::PluginActivator::stop(ctkPluginContext* context) { Q_UNUSED(context) m_Context = nullptr; } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.python/src/internal/mitkPluginActivator.h b/Plugins/org.mitk.gui.qt.diffusionimaging.python/src/internal/mitkPluginActivator.h new file mode 100644 index 0000000000..2867726397 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.python/src/internal/mitkPluginActivator.h @@ -0,0 +1,40 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ +#ifndef MITKPLUGINACTIVATOR_H +#define MITKPLUGINACTIVATOR_H + +#include + +namespace mitk +{ + class PluginActivator : public QObject, public ctkPluginActivator + { + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.mitk.gui.qt.diffusionimaging.preprocessing") + Q_INTERFACES(ctkPluginActivator) + + public: + static ctkPluginContext* GetContext(); + + void start(ctkPluginContext* context) override; + void stop(ctkPluginContext* context) override; + + private: + static ctkPluginContext* m_Context; + }; +} + +#endif diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/manifest_headers.cmake b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/manifest_headers.cmake index 82ab334e31..649136a2f4 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/manifest_headers.cmake +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/manifest_headers.cmake @@ -1,5 +1,5 @@ set(Plugin-Name "MITK Reconstruction") set(Plugin-Version "1.0.0") set(Plugin-Vendor "DKFZ, Medical and Biological Informatics") set(Plugin-ContactAddress "http://www.mitk.org") -set(Require-Plugin org.mitk.gui.qt.diffusionimaging org.mitk.gui.qt.common.legacy org.mitk.gui.qt.common) +set(Require-Plugin org.mitk.gui.qt.diffusionimaging org.mitk.gui.qt.common) diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/documentation/UserManual/QmitkDiffusionImagingRegistration.dox b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/documentation/UserManual/QmitkHeadMotionCorrection.dox similarity index 76% rename from Plugins/org.mitk.gui.qt.diffusionimaging.registration/documentation/UserManual/QmitkDiffusionImagingRegistration.dox rename to Plugins/org.mitk.gui.qt.diffusionimaging.registration/documentation/UserManual/QmitkHeadMotionCorrection.dox index 90e4f6f551..0b98310a5f 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/documentation/UserManual/QmitkDiffusionImagingRegistration.dox +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/documentation/UserManual/QmitkHeadMotionCorrection.dox @@ -1,5 +1,5 @@ /** -\page org_mitk_views_diffusionregistrationview Head-Motion Correction +\page org_mitk_views_headmotioncorrectionview Head-Motion Correction This view allows head-motion and eddy-current correction by affinely registering all volumes to the first unweighted volume of the complete diffusion-weighted image. The individual gradient directions are roated accordingly. */ diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/documentation/UserManual/QmitkSimpleRegistration.dox b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/documentation/UserManual/QmitkSimpleRegistration.dox new file mode 100644 index 0000000000..50f5be7cdd --- /dev/null +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/documentation/UserManual/QmitkSimpleRegistration.dox @@ -0,0 +1,8 @@ +/** +\page org_mitk_views_simpleregistrationview Registration + +This view enables the simple rigid or affine registration of two images. The registered image will be displayed in transparent blue color overlayed over the fixed image. To regain normal coloring, right-click on the data node and adjust the corresponding settings. + +It is also possible to transform a tractogram with a registration object obtained from a previous registration of two images. + +*/ diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/documentation/UserManual/QmitkSimpleRigidRegistration.dox b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/documentation/UserManual/QmitkSimpleRigidRegistration.dox deleted file mode 100644 index d98878e5a2..0000000000 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/documentation/UserManual/QmitkSimpleRigidRegistration.dox +++ /dev/null @@ -1,5 +0,0 @@ -/** -\page org_mitk_views_simplerigidregistrationview Rigid Registration - -This view enables the simple rigid registration of two images. The registered image will be displayed in transparent blue color overlayed over the fixed image. To regain normal coloring, right-click on the data node and adjust the corresponding settings. -*/ diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/files.cmake b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/files.cmake index b20be9d47b..88ebeda4b0 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/files.cmake +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/files.cmake @@ -1,46 +1,46 @@ set(SRC_CPP_FILES ) set(INTERNAL_CPP_FILES mitkPluginActivator.cpp - QmitkDiffusionRegistrationView.cpp - QmitkSimpleRigidRegistrationView.cpp + QmitkHeadMotionCorrectionView.cpp + QmitkSimpleRegistrationView.cpp QmitkDwiRegistrationPerspective.cpp ) set(UI_FILES - src/internal/QmitkDiffusionRegistrationViewControls.ui - src/internal/QmitkSimpleRigidRegistrationViewControls.ui + src/internal/QmitkHeadMotionCorrectionViewControls.ui + src/internal/QmitkSimpleRegistrationViewControls.ui ) set(MOC_H_FILES src/internal/mitkPluginActivator.h - src/internal/QmitkDiffusionRegistrationView.h - src/internal/QmitkSimpleRigidRegistrationView.h + src/internal/QmitkHeadMotionCorrectionView.h + src/internal/QmitkSimpleRegistrationView.h src/internal/QmitkDwiRegistrationPerspective.h ) set(CACHED_RESOURCE_FILES plugin.xml resources/diffusionregistration.png ) 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.diffusionimaging.registration/manifest_headers.cmake b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/manifest_headers.cmake index d54299c5e7..226f6402e8 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/manifest_headers.cmake +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/manifest_headers.cmake @@ -1,5 +1,5 @@ set(Plugin-Name "MITK dMRI Registration") set(Plugin-Version "1.0.0") set(Plugin-Vendor "DKFZ, Medical and Biological Informatics") set(Plugin-ContactAddress "http://www.mitk.org") -set(Require-Plugin org.mitk.gui.qt.diffusionimaging org.mitk.gui.qt.common.legacy org.mitk.gui.qt.common) +set(Require-Plugin org.mitk.gui.qt.diffusionimaging org.mitk.gui.qt.common) diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/plugin.xml b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/plugin.xml index 3a030cdea7..c66c507de8 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/plugin.xml +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/plugin.xml @@ -1,52 +1,52 @@ - - + - - + This perspective contains views for rigid image registration and head motion correction. - - - - - - - - + + + + + + + + - + diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkDwiRegistrationPerspective.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkDwiRegistrationPerspective.cpp index a5762d2bd2..ed5f3f8a56 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkDwiRegistrationPerspective.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkDwiRegistrationPerspective.cpp @@ -1,49 +1,49 @@ /*=================================================================== 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 "QmitkDwiRegistrationPerspective.h" #include "berryIViewLayout.h" void QmitkDwiRegistrationPerspective::CreateInitialLayout(berry::IPageLayout::Pointer layout) { ///////////////////////////////////////////////////// // all di-app perspectives should have the following: ///////////////////////////////////////////////////// QString editorArea = layout->GetEditorArea(); layout->AddStandaloneViewPlaceholder("org.mitk.views.viewnavigatorview", berry::IPageLayout::LEFT, 0.3f, editorArea, false); layout->AddStandaloneView("org.mitk.views.datamanager", false, berry::IPageLayout::LEFT, 0.3f, editorArea); layout->AddStandaloneView("org.mitk.views.controlvisualizationpropertiesview", false, berry::IPageLayout::BOTTOM, .15f, "org.mitk.views.datamanager"); berry::IFolderLayout::Pointer left = layout->CreateFolder("org.mbi.diffusionimaginginternal.leftcontrols", berry::IPageLayout::BOTTOM, 0.15f, "org.mitk.views.controlvisualizationpropertiesview"); layout->AddStandaloneViewPlaceholder("org.mitk.views.imagenavigator", berry::IPageLayout::BOTTOM, .7f, "org.mbi.diffusionimaginginternal.leftcontrols", false); ///////////////////////////////////////////// // here goes the perspective specific stuff ///////////////////////////////////////////// - left->AddView("org.mitk.views.simplerigidregistrationview"); - left->AddView("org.mitk.views.diffusionregistrationview"); + left->AddView("org.mitk.views.simpleregistrationview"); + left->AddView("org.mitk.views.headmotioncorrectionview"); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkDiffusionRegistrationView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkHeadMotionCorrectionView.cpp similarity index 81% rename from Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkDiffusionRegistrationView.cpp rename to Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkHeadMotionCorrectionView.cpp index e004e5dd4a..322f900ba4 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkDiffusionRegistrationView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkHeadMotionCorrectionView.cpp @@ -1,124 +1,124 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ //misc #define _USE_MATH_DEFINES #include // Blueberry #include #include // Qmitk -#include "QmitkDiffusionRegistrationView.h" +#include "QmitkHeadMotionCorrectionView.h" // MITK #include #include // Qt #include #include #include #include #include #include #define _USE_MATH_DEFINES #include -const std::string QmitkDiffusionRegistrationView::VIEW_ID = "org.mitk.views.diffusionregistrationview"; +const std::string QmitkHeadMotionCorrectionView::VIEW_ID = "org.mitk.views.headmotioncorrectionview"; -QmitkDiffusionRegistrationView::QmitkDiffusionRegistrationView() +QmitkHeadMotionCorrectionView::QmitkHeadMotionCorrectionView() : QmitkAbstractView() , m_Controls( 0 ) , m_DiffusionImage( nullptr ) { } // Destructor -QmitkDiffusionRegistrationView::~QmitkDiffusionRegistrationView() +QmitkHeadMotionCorrectionView::~QmitkHeadMotionCorrectionView() { } -void QmitkDiffusionRegistrationView::CreateQtPartControl( QWidget *parent ) +void QmitkHeadMotionCorrectionView::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::QmitkDiffusionRegistrationViewControls; + m_Controls = new Ui::QmitkHeadMotionCorrectionViewControls; m_Controls->setupUi( parent ); connect( m_Controls->m_ImageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGUI()) ); connect( m_Controls->m_RegistrationStartButton, SIGNAL(clicked()), this, SLOT(StartRegistration()) ); this->m_Parent = parent; m_Controls->m_ImageBox->SetDataStorage(this->GetDataStorage()); mitk::TNodePredicateDataType::Pointer isImagePredicate = mitk::TNodePredicateDataType::New(); m_Controls->m_ImageBox->SetPredicate(isImagePredicate); UpdateGUI(); } } -void QmitkDiffusionRegistrationView::OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList& ) +void QmitkHeadMotionCorrectionView::OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList& ) { } -void QmitkDiffusionRegistrationView::UpdateGUI() +void QmitkHeadMotionCorrectionView::UpdateGUI() { if (m_Controls->m_ImageBox->GetSelectedNode().IsNotNull()) { m_Controls->m_RegistrationStartButton->setEnabled(true); m_Controls->m_RegistrationStartButton->setToolTip("Start Registration"); } else { m_Controls->m_RegistrationStartButton->setEnabled(false); m_Controls->m_RegistrationStartButton->setToolTip("No Diffusion image selected."); } } -void QmitkDiffusionRegistrationView::SetFocus() +void QmitkHeadMotionCorrectionView::SetFocus() { UpdateGUI(); m_Controls->m_RegistrationStartButton->setFocus(); } -void QmitkDiffusionRegistrationView::StartRegistration() +void QmitkHeadMotionCorrectionView::StartRegistration() { mitk::DataNode::Pointer node = m_Controls->m_ImageBox->GetSelectedNode(); mitk::Image::Pointer inImage = dynamic_cast(node->GetData()); if (!mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(inImage)) { QMessageBox::warning(nullptr, "Warning", "Input node is not a diffusion-weighted image!"); return; } DWIHeadMotionCorrectionFilterType::Pointer registerer = DWIHeadMotionCorrectionFilterType::New(); registerer->SetInput(inImage); registerer->Update(); mitk::Image::Pointer image = registerer->GetCorrectedImage(); mitk::DataNode::Pointer corrected_node = mitk::DataNode::New(); corrected_node->SetData( image ); QString name(node->GetName().c_str()); name += "_Corrected"; corrected_node->SetName(name.toStdString()); GetDataStorage()->Add(corrected_node, node); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkDiffusionRegistrationView.h b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkHeadMotionCorrectionView.h similarity index 88% rename from Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkDiffusionRegistrationView.h rename to Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkHeadMotionCorrectionView.h index 999723a38d..d849893c05 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkDiffusionRegistrationView.h +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkHeadMotionCorrectionView.h @@ -1,78 +1,78 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include -#include "ui_QmitkDiffusionRegistrationViewControls.h" +#include "ui_QmitkHeadMotionCorrectionViewControls.h" #include #include #include #include typedef short DiffusionPixelType; /*! \brief View for diffusion image registration / head motion correction */ -class QmitkDiffusionRegistrationView : public QmitkAbstractView +class QmitkHeadMotionCorrectionView : public QmitkAbstractView { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: static const std::string VIEW_ID; - QmitkDiffusionRegistrationView(); - virtual ~QmitkDiffusionRegistrationView(); + QmitkHeadMotionCorrectionView(); + virtual ~QmitkHeadMotionCorrectionView(); virtual void CreateQtPartControl(QWidget *parent) override; void SetFocus() override; typedef mitk::DWIHeadMotionCorrectionFilter DWIHeadMotionCorrectionFilterType; protected slots: void StartRegistration(); void UpdateGUI(); ///< update button activity etc. dpending on current datamanager selection protected: /// \brief called by QmitkAbstractView when DataManager's selection has changed virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList& nodes) override; - Ui::QmitkDiffusionRegistrationViewControls* m_Controls; + Ui::QmitkHeadMotionCorrectionViewControls* m_Controls; mitk::Image::Pointer m_DiffusionImage; std::vector< mitk::DataNode::Pointer > m_SelectedDiffusionNodes; private: void UpdateRegistrationStatus(); ///< update textual status display of the Registration process // the Qt parent of our GUI (NOT of this object) QWidget* m_Parent; }; diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkDiffusionRegistrationViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkHeadMotionCorrectionViewControls.ui similarity index 92% rename from Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkDiffusionRegistrationViewControls.ui rename to Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkHeadMotionCorrectionViewControls.ui index f051e3f25c..a86cc9f1e0 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkDiffusionRegistrationViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkHeadMotionCorrectionViewControls.ui @@ -1,88 +1,88 @@ - QmitkDiffusionRegistrationViewControls - + QmitkHeadMotionCorrectionViewControls + 0 0 435 744 Form 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
+
QmitkDataStorageComboBox.h
diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkSimpleRigidRegistrationView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkSimpleRegistrationView.cpp similarity index 54% rename from Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkSimpleRigidRegistrationView.cpp rename to Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkSimpleRegistrationView.cpp index 2954bc3839..c13e1f5199 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkSimpleRigidRegistrationView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkSimpleRegistrationView.cpp @@ -1,275 +1,388 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ //misc #define _USE_MATH_DEFINES #include // Blueberry #include #include // Qmitk -#include "QmitkSimpleRigidRegistrationView.h" +#include "QmitkSimpleRegistrationView.h" // MITK #include #include #include #include #include #include +#include +#include +#include +#include +#include // Qt #include #define _USE_MATH_DEFINES #include -const std::string QmitkSimpleRigidRegistrationView::VIEW_ID = "org.mitk.views.simplerigidregistrationview"; +const std::string QmitkSimpleRegistrationView::VIEW_ID = "org.mitk.views.simpleregistrationview"; -QmitkSimpleRigidRegistrationView::QmitkSimpleRigidRegistrationView() +QmitkSimpleRegistrationView::QmitkSimpleRegistrationView() : QmitkAbstractView() , m_Controls( 0 ) + , m_RegistrationType(0) { } // Destructor -QmitkSimpleRigidRegistrationView::~QmitkSimpleRigidRegistrationView() +QmitkSimpleRegistrationView::~QmitkSimpleRegistrationView() { } -void QmitkSimpleRigidRegistrationView::StartRegistration() +void QmitkSimpleRegistrationView::StartRegistration() { - typedef itk::Image< float, 3 > ItkFloatImageType; - mitk::MultiModalRigidDefaultRegistrationAlgorithm< ItkFloatImageType >::Pointer algo = mitk::MultiModalRigidDefaultRegistrationAlgorithm< ItkFloatImageType >::New(); + QmitkRegistrationJob* pJob; + + if (m_Controls->m_RegBox->currentIndex()==0) + { + mitk::MultiModalRigidDefaultRegistrationAlgorithm< ItkFloatImageType >::Pointer algo = mitk::MultiModalRigidDefaultRegistrationAlgorithm< ItkFloatImageType >::New(); + pJob = new QmitkRegistrationJob(algo); + m_RegistrationType = 0; + } + else + { + mitk::MultiModalAffineDefaultRegistrationAlgorithm< ItkFloatImageType >::Pointer algo = mitk::MultiModalAffineDefaultRegistrationAlgorithm< ItkFloatImageType >::New(); + pJob = new QmitkRegistrationJob(algo); + m_RegistrationType = 1; + } - QmitkRegistrationJob* pJob = new QmitkRegistrationJob(algo); pJob->setAutoDelete(true); m_MovingImageNode = m_Controls->m_MovingImageBox->GetSelectedNode(); mitk::Image::Pointer movingImage = dynamic_cast(m_MovingImageNode->GetData()); if (mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(movingImage)) { ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(movingImage, itkVectorImagePointer); itk::ExtractDwiChannelFilter< short >::Pointer filter = itk::ExtractDwiChannelFilter< short >::New(); filter->SetInput( itkVectorImagePointer); filter->SetChannelIndex(m_Controls->m_MovingChannelBox->value()); filter->Update(); mitk::Image::Pointer newImage = mitk::Image::New(); newImage->InitializeByItk( filter->GetOutput() ); newImage->SetImportChannel( filter->GetOutput()->GetBufferPointer() ); pJob->m_spMovingData = newImage; } else pJob->m_spMovingData = movingImage; mitk::Image::Pointer fixedImage = dynamic_cast(m_Controls->m_FixedImageBox->GetSelectedNode()->GetData()); if (mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(fixedImage)) { ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(fixedImage, itkVectorImagePointer); itk::ExtractDwiChannelFilter< short >::Pointer filter = itk::ExtractDwiChannelFilter< short >::New(); filter->SetInput( itkVectorImagePointer); filter->SetChannelIndex(m_Controls->m_MovingChannelBox->value()); filter->Update(); mitk::Image::Pointer newImage = mitk::Image::New(); newImage->InitializeByItk( filter->GetOutput() ); newImage->SetImportChannel( filter->GetOutput()->GetBufferPointer() ); pJob->m_spTargetData = newImage; } else pJob->m_spTargetData = fixedImage; pJob->m_TargetDataUID = mitk::EnsureUID(m_Controls->m_FixedImageBox->GetSelectedNode()->GetData()); pJob->m_MovingDataUID = mitk::EnsureUID(m_Controls->m_MovingImageBox->GetSelectedNode()->GetData()); connect(pJob, SIGNAL(RegResultIsAvailable(mitk::MAPRegistrationWrapper::Pointer, const QmitkRegistrationJob*)), this, SLOT(OnRegResultIsAvailable(mitk::MAPRegistrationWrapper::Pointer, const QmitkRegistrationJob*)), Qt::BlockingQueuedConnection); -// connect(pJob, SIGNAL(AlgorithmInfo(QString)), this, SLOT(OnAlgorithmInfo(QString))); -// connect(pJob, SIGNAL(AlgorithmStatusChanged(QString)), this, SLOT(OnAlgorithmStatusChanged(QString))); -// connect(pJob, SIGNAL(AlgorithmIterated(QString, bool, unsigned long)), this, SLOT(OnAlgorithmIterated(QString, bool, unsigned long))); -// connect(pJob, SIGNAL(LevelChanged(QString, bool, unsigned long)), this, SLOT(OnLevelChanged(QString, bool, unsigned long))); - QThreadPool* threadPool = QThreadPool::globalInstance(); threadPool->start(pJob); m_Controls->m_RegistrationStartButton->setEnabled(false); m_Controls->m_RegistrationStartButton->setText("Registration in progress ..."); } -void QmitkSimpleRigidRegistrationView::OnRegResultIsAvailable(mitk::MAPRegistrationWrapper::Pointer spResultRegistration, const QmitkRegistrationJob* ) +void QmitkSimpleRegistrationView::OnRegResultIsAvailable(mitk::MAPRegistrationWrapper::Pointer spResultRegistration, const QmitkRegistrationJob* job) { mitk::Image::Pointer movingImage = dynamic_cast(m_MovingImageNode->GetData()); - mitk::Image::Pointer image = mitk::ImageMappingHelper::refineGeometry(movingImage, spResultRegistration, true); + mitk::Image::Pointer image; + + if (m_RegistrationType==0) + { + image = mitk::ImageMappingHelper::refineGeometry(movingImage, spResultRegistration, true); + } + else + { + if (!mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(movingImage)) + { + image = mitk::ImageMappingHelper::map(movingImage, spResultRegistration, false, 0, job->m_spTargetData->GetGeometry(), false, 0, mitk::ImageMappingInterpolator::BSpline_3); + } + else + { + typedef itk::ComposeImageFilter < ITKDiffusionVolumeType > ComposeFilterType; + ComposeFilterType::Pointer composer = ComposeFilterType::New(); + + ItkDwiType::Pointer itkVectorImagePointer = mitk::DiffusionPropertyHelper::GetItkVectorImage(movingImage); + for (unsigned int i=0; iGetVectorLength(); ++i) + { + itk::ExtractDwiChannelFilter< short >::Pointer filter = itk::ExtractDwiChannelFilter< short >::New(); + filter->SetInput( itkVectorImagePointer); + filter->SetChannelIndex(i); + filter->Update(); + + mitk::Image::Pointer gradientVolume = mitk::Image::New(); + gradientVolume->InitializeByItk( filter->GetOutput() ); + gradientVolume->SetImportChannel( filter->GetOutput()->GetBufferPointer() ); + + mitk::Image::Pointer registered_mitk_image = mitk::ImageMappingHelper::map(gradientVolume, spResultRegistration, false, 0, job->m_spTargetData->GetGeometry(), false, 0, mitk::ImageMappingInterpolator::BSpline_3); + + ITKDiffusionVolumeType::Pointer registered_itk_image = ITKDiffusionVolumeType::New(); + mitk::CastToItkImage(registered_mitk_image, registered_itk_image); + composer->SetInput(i, registered_itk_image); + } + + composer->Update(); + + image = mitk::GrabItkImageMemory( composer->GetOutput() ); + mitk::DiffusionPropertyHelper::CopyProperties(movingImage, image, true); + } + } if (mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(image)) { mitk::DiffusionPropertyHelper propertyHelper( image ); propertyHelper.InitializeImage(); } mitk::DataNode::Pointer resultNode = mitk::DataNode::New(); resultNode->SetData(image); if (m_MovingImageNode.IsNotNull()) { m_MovingImageNode->SetVisibility(false); QString name = m_MovingImageNode->GetName().c_str(); - resultNode->SetName((name+"_registered").toStdString().c_str()); + if (m_RegistrationType==0) + resultNode->SetName((name+"_registered (rigid)").toStdString().c_str()); + else + resultNode->SetName((name+"_registered (affine)").toStdString().c_str()); } else - resultNode->SetName("Registered"); + { + if (m_RegistrationType==0) + resultNode->SetName("Registered (rigid)"); + else + resultNode->SetName("Registered (affine)"); + } resultNode->SetOpacity(0.6); resultNode->SetColor(0.0, 0.0, 1.0); - GetDataStorage()->Add(resultNode); + if (m_Controls->m_RegOutputBox->isChecked()) + { + mitk::DataNode::Pointer registration_node = mitk::DataNode::New(); + registration_node->SetData(spResultRegistration); + if (m_RegistrationType==0) + registration_node->SetName("Registration Object (rigid)"); + else + registration_node->SetName("Registration Object (affine)"); + GetDataStorage()->Add(registration_node, resultNode); + } + this->GetRenderWindowPart()->RequestUpdate(); m_Controls->m_RegistrationStartButton->setEnabled(true); m_Controls->m_RegistrationStartButton->setText("Start Registration"); m_MovingImageNode = nullptr; + + TractoChanged(); } -void QmitkSimpleRigidRegistrationView::CreateQtPartControl( QWidget *parent ) +void QmitkSimpleRegistrationView::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::QmitkSimpleRigidRegistrationViewControls; + m_Controls = new Ui::QmitkSimpleRegistrationViewControls; m_Controls->setupUi( parent ); m_Controls->m_FixedImageBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_MovingImageBox->SetDataStorage(this->GetDataStorage()); mitk::TNodePredicateDataType::Pointer isImagePredicate = mitk::TNodePredicateDataType::New(); m_Controls->m_FixedImageBox->SetPredicate(isImagePredicate); m_Controls->m_MovingImageBox->SetPredicate(isImagePredicate); + mitk::TNodePredicateDataType::Pointer isFib = mitk::TNodePredicateDataType::New(); + mitk::TNodePredicateDataType::Pointer isReg = mitk::TNodePredicateDataType::New(); + + m_Controls->m_TractoBox->SetDataStorage(this->GetDataStorage()); + m_Controls->m_RegObjectBox->SetDataStorage(this->GetDataStorage()); + m_Controls->m_TractoBox->SetPredicate(isFib); + m_Controls->m_RegObjectBox->SetPredicate(isReg); + connect( m_Controls->m_FixedImageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(FixedImageChanged()) ); connect( m_Controls->m_MovingImageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(MovingImageChanged()) ); + + connect( m_Controls->m_TractoBox, SIGNAL(currentIndexChanged(int)), this, SLOT(TractoChanged()) ); + connect( m_Controls->m_RegObjectBox, SIGNAL(currentIndexChanged(int)), this, SLOT(TractoChanged()) ); + connect( m_Controls->m_RegistrationStartButton, SIGNAL(clicked()), this, SLOT(StartRegistration()) ); + connect( m_Controls->m_TractoRegistrationStartButton, SIGNAL(clicked()), this, SLOT(StartTractoRegistration()) ); FixedImageChanged(); MovingImageChanged(); + TractoChanged(); } } -void QmitkSimpleRigidRegistrationView::FixedImageChanged() +void QmitkSimpleRegistrationView::StartTractoRegistration() +{ + mitk::FiberBundle::Pointer fib = dynamic_cast(m_Controls->m_TractoBox->GetSelectedNode()->GetData()); + mitk::MAPRegistrationWrapper::Pointer reg = dynamic_cast(m_Controls->m_RegObjectBox->GetSelectedNode()->GetData()); + + mitk::MITKRegistrationHelper::Affine3DTransformType::Pointer affine = mitk::MITKRegistrationHelper::getAffineMatrix(reg, false); + + mitk::FiberBundle::Pointer fib_copy = fib->GetDeepCopy(); + fib_copy->TransformFibers(affine); + + mitk::DataNode::Pointer registration_node = mitk::DataNode::New(); + registration_node->SetData(fib_copy); + QString name = m_Controls->m_TractoBox->GetSelectedNode()->GetName().c_str(); + registration_node->SetName((name+"_registered").toStdString().c_str()); + GetDataStorage()->Add(registration_node, m_Controls->m_TractoBox->GetSelectedNode()); +} + +void QmitkSimpleRegistrationView::TractoChanged() +{ + if (m_Controls->m_RegObjectBox->GetSelectedNode().IsNotNull() && m_Controls->m_TractoBox->GetSelectedNode().IsNotNull()) + m_Controls->m_TractoRegistrationStartButton->setEnabled(true); + else + m_Controls->m_TractoRegistrationStartButton->setEnabled(false); +} + +void QmitkSimpleRegistrationView::FixedImageChanged() { if (m_Controls->m_FixedImageBox->GetSelectedNode().IsNotNull()) { mitk::Image::Pointer image = dynamic_cast(m_Controls->m_FixedImageBox->GetSelectedNode()->GetData()); int channels = image->GetNumberOfChannels(); int dims = image->GetDimension(); int fourth_dim_size = image->GetTimeSteps(); bool isdiff = mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(image); if (dims==4 || channels>1) { m_Controls->m_FixedChannelBox->setEnabled(false); m_Controls->m_RegistrationStartButton->setEnabled(false); } if (isdiff) { m_Controls->m_FixedChannelBox->setEnabled(true); if (fourth_dim_size>1) m_Controls->m_FixedChannelBox->setMaximum(fourth_dim_size-1); else if (isdiff) m_Controls->m_FixedChannelBox->setMaximum(mitk::DiffusionPropertyHelper::GetGradientContainer(image)->Size()-1); } else { m_Controls->m_FixedChannelBox->setEnabled(false); } m_Controls->m_RegistrationStartButton->setEnabled(true); } else { m_Controls->m_FixedChannelBox->setEnabled(false); m_Controls->m_RegistrationStartButton->setEnabled(false); } } -void QmitkSimpleRigidRegistrationView::MovingImageChanged() +void QmitkSimpleRegistrationView::MovingImageChanged() { if (m_Controls->m_MovingImageBox->GetSelectedNode().IsNotNull()) { mitk::Image::Pointer image = dynamic_cast(m_Controls->m_MovingImageBox->GetSelectedNode()->GetData()); int channels = image->GetNumberOfChannels(); int dims = image->GetDimension(); int fourth_dim_size = image->GetTimeSteps(); bool isdiff = mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(image); if (dims==4 || channels>1) { m_Controls->m_MovingChannelBox->setEnabled(false); m_Controls->m_RegistrationStartButton->setEnabled(false); } if (isdiff) { m_Controls->m_MovingChannelBox->setEnabled(true); if (fourth_dim_size>1) m_Controls->m_MovingChannelBox->setMaximum(fourth_dim_size-1); else if (isdiff) m_Controls->m_MovingChannelBox->setMaximum(mitk::DiffusionPropertyHelper::GetGradientContainer(image)->Size()-1); } else { m_Controls->m_MovingChannelBox->setEnabled(false); } m_Controls->m_RegistrationStartButton->setEnabled(true); } else { m_Controls->m_MovingChannelBox->setEnabled(false); m_Controls->m_RegistrationStartButton->setEnabled(false); } } -void QmitkSimpleRigidRegistrationView::OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList& ) +void QmitkSimpleRegistrationView::OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList& ) { FixedImageChanged(); MovingImageChanged(); + TractoChanged(); } -void QmitkSimpleRigidRegistrationView::SetFocus() +void QmitkSimpleRegistrationView::SetFocus() { m_Controls->m_RegistrationStartButton->setFocus(); FixedImageChanged(); MovingImageChanged(); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkSimpleRigidRegistrationView.h b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkSimpleRegistrationView.h similarity index 78% rename from Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkSimpleRigidRegistrationView.h rename to Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkSimpleRegistrationView.h index 23f278e3f4..777508b956 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkSimpleRigidRegistrationView.h +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkSimpleRegistrationView.h @@ -1,71 +1,75 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include -#include "ui_QmitkSimpleRigidRegistrationViewControls.h" +#include "ui_QmitkSimpleRegistrationViewControls.h" #include #include -#include typedef short DiffusionPixelType; /*! \brief View for diffusion image registration / head motion correction */ // Forward Qt class declarations -class QmitkSimpleRigidRegistrationView : public QmitkAbstractView +class QmitkSimpleRegistrationView : public QmitkAbstractView { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: + typedef itk::Image< float, 3 > ItkFloatImageType; + typedef itk::Image ITKDiffusionVolumeType; typedef itk::VectorImage< short, 3 > ItkDwiType; static const std::string VIEW_ID; - QmitkSimpleRigidRegistrationView(); - virtual ~QmitkSimpleRigidRegistrationView(); + QmitkSimpleRegistrationView(); + virtual ~QmitkSimpleRegistrationView(); virtual void CreateQtPartControl(QWidget *parent) override; void SetFocus() override; protected slots: void MovingImageChanged(); void FixedImageChanged(); + void TractoChanged(); void StartRegistration(); + void StartTractoRegistration(); void OnRegResultIsAvailable(mitk::MAPRegistrationWrapper::Pointer spResultRegistration, const QmitkRegistrationJob* pRegJob); protected: /// \brief called by QmitkAbstractView when DataManager's selection has changed virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList& nodes) override; - Ui::QmitkSimpleRigidRegistrationViewControls* m_Controls; + Ui::QmitkSimpleRegistrationViewControls* m_Controls; mitk::DataNode::Pointer m_MovingImageNode; + int m_RegistrationType; private: }; 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 new file mode 100644 index 0000000000..67cb63db27 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkSimpleRegistrationViewControls.ui @@ -0,0 +1,231 @@ + + + QmitkSimpleRegistrationViewControls + + + + 0 + 0 + 435 + 744 + + + + Form + + + + + + 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: + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + Rigid + + + + + Affine + + + + + + + + Registration Type: + + + + + + + + + + + + + + Output Registration Object: + + + + + + + + + + false + + + + + + Start Registration + + + + + + + Tractography Registration + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Registration Object: + + + + + + + + + + Tractogram: + + + + + + + + + + + + + false + + + + + + Start Tractography Registration + + + + + + + + QmitkDataStorageComboBox + QComboBox +
QmitkDataStorageComboBox.h
+
+
+ + +
diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkSimpleRigidRegistrationViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkSimpleRigidRegistrationViewControls.ui deleted file mode 100644 index 38a25a4afe..0000000000 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkSimpleRigidRegistrationViewControls.ui +++ /dev/null @@ -1,118 +0,0 @@ - - - QmitkSimpleRigidRegistrationViewControls - - - - 0 - 0 - 435 - 744 - - - - Form - - - - - - QFrame::NoFrame - - - QFrame::Raised - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - Moving Image: - - - - - - - Fixed Image: - - - - - - - - - - false - - - Select dMRI volume used to calculate transformation. - - - - - - - false - - - Select dMRI volume used to calculate transformation. - - - - - - - - - - false - - - - - - Start Registration - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - QmitkDataStorageComboBox - QComboBox -
QmitkDataStorageComboBox.h
-
-
- - -
diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/mitkPluginActivator.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/mitkPluginActivator.cpp index 581c7cf5d6..ee12c7bdca 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/mitkPluginActivator.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/mitkPluginActivator.cpp @@ -1,43 +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. ===================================================================*/ #include "mitkPluginActivator.h" -#include "src/internal/QmitkDiffusionRegistrationView.h" -#include "src/internal/QmitkSimpleRigidRegistrationView.h" +#include "src/internal/QmitkHeadMotionCorrectionView.h" +#include "src/internal/QmitkSimpleRegistrationView.h" #include "src/internal/QmitkDwiRegistrationPerspective.h" ctkPluginContext* mitk::PluginActivator::m_Context = nullptr; ctkPluginContext* mitk::PluginActivator::GetContext() { return m_Context; } void mitk::PluginActivator::start(ctkPluginContext* context) { - BERRY_REGISTER_EXTENSION_CLASS(QmitkDiffusionRegistrationView, context) - BERRY_REGISTER_EXTENSION_CLASS(QmitkSimpleRigidRegistrationView, context) + BERRY_REGISTER_EXTENSION_CLASS(QmitkHeadMotionCorrectionView, context) + BERRY_REGISTER_EXTENSION_CLASS(QmitkSimpleRegistrationView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkDwiRegistrationPerspective, context) m_Context = context; } void mitk::PluginActivator::stop(ctkPluginContext* context) { Q_UNUSED(context) m_Context = nullptr; } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/manifest_headers.cmake b/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/manifest_headers.cmake index 3e69df27ff..5c107a6272 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/manifest_headers.cmake +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/manifest_headers.cmake @@ -1,5 +1,5 @@ set(Plugin-Name "MITK Tbss") set(Plugin-Version "1.0.0") set(Plugin-Vendor "DKFZ, Medical and Biological Informatics") set(Plugin-ContactAddress "http://www.mitk.org") -set(Require-Plugin org.mitk.gui.qt.diffusionimaging org.mitk.gui.qt.common.legacy org.mitk.gui.qt.common) +set(Require-Plugin org.mitk.gui.qt.diffusionimaging org.mitk.gui.qt.common) diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/documentation/UserManual/QmitkStreamlineTrackingViewUserManual.dox b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/documentation/UserManual/QmitkStreamlineTrackingViewUserManual.dox index e19a991a1f..eb0ed3b82f 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/documentation/UserManual/QmitkStreamlineTrackingViewUserManual.dox +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/documentation/UserManual/QmitkStreamlineTrackingViewUserManual.dox @@ -1,74 +1,74 @@ /** \page org_mitk_views_streamlinetracking Streamline Tractography This view enables streamline tractography on various input data. The corresponding command line application is named "MitkStreamlineTractography". Available sections: - \ref StrTrackUserManualInputData - \ref StrTrackUserManualInteractive - \ref StrTrackUserManualParameters - \ref StrTrackUserManualAdvancedParameters - \ref StrTrackUserManualReferences \section StrTrackUserManualInputData Input Data Input: Select the data you want to track on in the datamanager. Supported file types are: \li One or multiple DTI images selected in the datamanager. \li One ODF image, e.g. obtained using MITK Q-ball reconstruction or MRtrix CSD (tractography similar to [6]). \li One peak image (4D float image). \li One raw diffusion-weighted image for machine learning based tractography [1]. Optional Input: \li Binary mask used to define the seed voxels. If no seed mask is specified, the whole image volume is seeded. \li Binary mask used to constrain the generated streamlines. Streamlines can not leave the mask area. \li Binary mask used to define stopping regions. Streamlines that enter the mask area are stopped immediately. \li Tissue label image needed for gray matter seeding (WM=3, GM=1). Use e.g. MRtrix 5ttgen to generate such a label image. \li FA/GFA image used to determine streamline termination. If no image is specified, the FA/GFA image is automatically calculated from the input image. If multiple tensor images are used as input, it is recommended to provide such an image since the FA maps calculated from the individual input tensor images can not provide a suitable termination criterion. \li Tractography Forest: Needed for machine learning based tractography [1]. \section StrTrackUserManualInteractive Interactive Tractography Interactive tractography enables the dynamic placement of spherical seed regions simply by clicking into the image (similar to [5]). Parameters are the number of seed points and the radius of the spherical seed region. The seed points are randomly distributed inside the sphere around the selected position. By clicking and holding the left mouse button while moving the mouse around the image, the fiber connections originating from the selected region can be explored dynamically. When "Update on Parameter Change" is checked, each parameter change causes an instant retracking with the new parameters. This enables an intuitive exploration of the effcts that the individual parameters have on the resulting tractogram. \section StrTrackUserManualParameters Parameters \li Mode: Toggle between deterministic and probabilistic tractography. Peak tracking only supports deterministic mode. The probabilistic method simply samples the output direction from the discrete probability ditribution provided by the discretized ODF. \li Seeds per voxel: If set to 1, the seed is defined as the voxel center. If > 1 the seeds are distributet randomly inside the voxel. \li Max. num. fibers: Tractography is stopped after the desired number of fibers is reached, even before all seed points are processed. \li Cutoff: If the streamline reaches a position with an FA value or peak magnitude lower than the speciefied threshold, tracking is terminated. Typical values are 0.2 for FA/GFA and 0.1 for CSD peaks. \li ODF Cutoff: Additional threshold on the ODF magnitude. This is useful in case of CSD fODF tractography. For MRtrix CSD fODF images, a typical value is 0.1. \li Sharpen ODFs: 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 (and not recommended) for CSD fODFs, since they are naturally much sharper. \section StrTrackUserManualAdvancedParameters Advanced Parameters \li Step Size: The algorithm proceeds along the streamline with a fixed stepsize. Default is 0.5*minSpacing. \li Angular threshold: Maximum angle between two successive steps (in degree). Default is 90° * step_size. For probabilistic tractography, candidate directions exceeding this threshold have probability 0, i.e. the respective ODF value is set to zero. The probabilities of the valid directions are normalized to sum to 1. \li Min. Tract Length: Shorter fibers are discarded. \li f and g values to balance between FACT [2] and TEND [3,4] tracking (only for tensor based tractography). For further information please refer to [2,3] \li Flip directions: Internally flips progression directions. This might be necessary depending on the input data. \li Enable Trilinear Interpolation: By default the image values are interpolated. Keep in mind that in the noninterpolated case, the TEND term is only applied once per voxel. In the interpolated case the TEND term is applied at each integration step which results in much higher curvatures and has to be compensated by an according choice of f and g. \li Enable Gray Matter Seeding: Seeds are onyl placed inside of the gray matter. Needs tissue label image. -\section StrTrackUserManualAdvancedParameters Neighbourhood Sampling (for details see [1]) +\section StrTrackUserManualNeighbourhoodSampling Neighbourhood Sampling (for details see [1]) \li Neighborhood Samples: Number of neighborhood samples that are used to determine the next fiber progression direction. \li Sampling Distance: Distance of the sampling positions from the current streamline position (in voxels). \li Use Only Frontal Samples: Only neighborhood samples in front of the current streamline position are considered. \li Use Stop-Votes: 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. -\section StrTrackUserManualAdvancedParameters Output and Postprocessing +\section StrTrackUserManualPostprocessing Output and Postprocessing \li Compress Fibers: Whole brain tractograms obtained with a small step size can contain billions of points. The tractograms can be compressed by removing points that do not really contribute to the fiber shape, such as many points on a straight line. An error threshold (in mm) can be defined to specify which points should be removed and which not. \li Output Probability Map: No streamline are generated. Instead, the tractography outputs a probability map that indicates the probability of a fiber to reach a voxel from the selected seed region. For this measure to be sensible, the number of seeds per voxel needs to be rather large. \section StrTrackUserManualReferences References [1] Neher, Peter F., Marc-Alexandre Côté, Jean-Christophe Houde, Maxime Descoteaux, and Klaus H. Maier-Hein. “Fiber Tractography Using Machine Learning.” NeuroImage. Accessed July 19, 2017. doi:10.1016/j.neuroimage.2017.07.028.\n [2] Mori, Susumu, Walter E. Kaufmann, Godfrey D. Pearlson, Barbara J. Crain, Bram Stieltjes, Meiyappan Solaiyappan, and Peter C. M. Van Zijl. “In Vivo Visualization of Human Neural Pathways by Magnetic Resonance Imaging.” Annals of Neurology 47 (2000): 412–414.\n [3] Weinstein, David, Gordon Kindlmann, and Eric Lundberg. “Tensorlines: Advection-Diffusion Based Propagation through Diffusion Tensor Fields.” In Proceedings of the Conference on Visualization’99: Celebrating Ten Years, 249–253, n.d.\n [4] Lazar, Mariana, David M. Weinstein, Jay S. Tsuruda, Khader M. Hasan, Konstantinos Arfanakis, M. Elizabeth Meyerand, Benham Badie, et al. “White Matter Tractography Using Diffusion Tensor Deflection.” Human Brain Mapping 18, no. 4 (2003): 306–321.\n [5] Chamberland, M., K. Whittingstall, D. Fortin, D. Mathieu, and M. Descoteaux. “Real-Time Multi-Peak Tractography for Instantaneous Connectivity Display.” Front Neuroinform 8 (2014): 59. doi:10.3389/fninf.2014.00059.\n [6] Tournier, J-Donald, Fernando Calamante, and Alan Connelly. “MRtrix: Diffusion Tractography in Crossing Fiber Regions.” International Journal of Imaging Systems and Technology 22, no. 1 (March 2012): 53–66. doi:10.1002/ima.22005. */ diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/manifest_headers.cmake b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/manifest_headers.cmake index 72c7b12377..b2dc929af8 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/manifest_headers.cmake +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/manifest_headers.cmake @@ -1,6 +1,5 @@ set(Plugin-Name "MITK Tractography") set(Plugin-Version "1.0.0") set(Plugin-Vendor "DKFZ, Medical and Biological Informatics") set(Plugin-ContactAddress "http://www.mitk.org") -set(Require-Plugin org.mitk.gui.qt.diffusionimaging org.mitk.gui.qt.common.legacy org.mitk.gui.qt.common) -set(Plugin-ActivationPolicy "eager") +set(Require-Plugin org.mitk.gui.qt.diffusionimaging org.mitk.gui.qt.common) diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkDiffusionImagingPortalPage.dox b/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkDiffusionImagingPortalPage.dox index 41cb380913..d2052b2ff2 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkDiffusionImagingPortalPage.dox +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkDiffusionImagingPortalPage.dox @@ -1,48 +1,48 @@ /** \page org_mitk_gui_qt_diffusionimaging MITK Diffusion \tableofcontents MITK Diffusion offers a selection of image analysis methods for dMRI processing. It encompasses the research of the Division of Medical Image Computing of the German Cancer Research Center (DKFZ). \section org_mitk_gui_qt_diffusionimagingComponents Components MITK Diffusion consists of multiple components with their own documentation: \subsection sub1 Data formats, import and export \li \subpage QmitkDiffusionImagingDataImportPage \subsection sub2 Preprocessing and Reconstruction \li \subpage org_mitk_views_diffusionpreprocessing -\li \subpage org_mitk_views_simplerigidregistrationview -\li \subpage org_mitk_views_diffusionregistrationview +\li \subpage org_mitk_views_simpleregistrationview +\li \subpage org_mitk_views_headmotioncorrectionview \li \subpage org_mitk_views_denoisingview \li \subpage org_mitk_views_tensorreconstruction \li \subpage org_mitk_views_qballreconstruction \subsection sub3 Visualization and Quantification \li \subpage org_mitk_views_controlvisualizationpropertiesview \li \subpage org_mitk_views_odfdetails \li \subpage org_mitk_views_odfmaximaextraction \li \subpage org_mitk_views_partialvolumeanalysisview \li \subpage org_mitk_views_diffusionquantification \li \subpage org_mitk_views_ivim \subsection sub4 Fiber Tractography \li \subpage org_mitk_views_streamlinetracking \li \subpage org_mitk_views_gibbstracking \li \subpage org_mitk_views_mlbtview \li \subpage org_mitk_views_fiberprocessing \li \subpage org_mitk_views_fiberquantification \li \subpage org_mitk_views_fiberfit \li \subpage org_mitk_views_fiberclustering \subsection sub5 Fiberfox dMRI Simulation \li \subpage org_mitk_views_fiberfoxview \li \subpage org_mitk_views_fieldmapgenerator \subsection sub6 TBSS and Connectomics \li \subpage org_mitk_views_tractbasedspatialstatistics \li \subpage org_mitk_diffusionimagingapp_perspectives_connectomics */ diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/manifest_headers.cmake b/Plugins/org.mitk.gui.qt.diffusionimaging/manifest_headers.cmake index 9fa658aee6..bdff16293f 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/manifest_headers.cmake +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/manifest_headers.cmake @@ -1,5 +1,6 @@ set(Plugin-Name "MITK Diffusion Imaging") set(Plugin-Version "0.1") set(Plugin-Vendor "DKFZ, Medical and Biological Informatics") set(Plugin-ContactAddress "http://www.mitk.org") -set(Require-Plugin org.mitk.gui.qt.common org.mitk.gui.qt.common) +set(Require-Plugin org.mitk.gui.qt.common) +#set(Plugin-ActivationPolicy eager) diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsCalculationThread.cpp b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsCalculationThread.cpp index 8c04776ac4..18d2d6c4d1 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsCalculationThread.cpp +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsCalculationThread.cpp @@ -1,275 +1,241 @@ /*=================================================================== 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 "QmitkImageStatisticsCalculationThread.h" //QT headers #include #include #include #include #include QmitkImageStatisticsCalculationThread::QmitkImageStatisticsCalculationThread() : QThread() , m_StatisticsImage(nullptr) , m_BinaryMask(nullptr) , m_PlanarFigureMask(nullptr) , m_TimeStep(0) , m_IgnoreZeros(false) , m_HistogramBinSize(10.0) , m_StatisticChanged(false) , m_CalculationSuccessful(false) - , m_UseDefaultNBins(true) - , m_nBinsForHistogramStatistics(100) - , m_prioritizeNBinsOverBinSize(true) { } QmitkImageStatisticsCalculationThread::~QmitkImageStatisticsCalculationThread() { } void QmitkImageStatisticsCalculationThread::Initialize( mitk::Image::Pointer image, mitk::Image::Pointer binaryImage, mitk::PlanarFigure::Pointer planarFig ) { // reset old values if( this->m_StatisticsImage.IsNotNull() ) this->m_StatisticsImage = nullptr; if( this->m_BinaryMask.IsNotNull() ) this->m_BinaryMask = nullptr; if( this->m_PlanarFigureMask.IsNotNull()) this->m_PlanarFigureMask = nullptr; // set new values if passed in if(image.IsNotNull()) this->m_StatisticsImage = image->Clone(); if(binaryImage.IsNotNull()) this->m_BinaryMask = binaryImage->Clone(); if(planarFig.IsNotNull()) this->m_PlanarFigureMask = planarFig->Clone(); } -void QmitkImageStatisticsCalculationThread::SetUseDefaultNBins(bool useDefault) -{ - m_UseDefaultNBins = useDefault; -} - void QmitkImageStatisticsCalculationThread::SetTimeStep( int times ) { this->m_TimeStep = times; } int QmitkImageStatisticsCalculationThread::GetTimeStep() { return this->m_TimeStep; } std::vector QmitkImageStatisticsCalculationThread::GetStatisticsData() { return this->m_StatisticsVector; } mitk::Image::Pointer QmitkImageStatisticsCalculationThread::GetStatisticsImage() { return this->m_StatisticsImage; } void QmitkImageStatisticsCalculationThread::SetIgnoreZeroValueVoxel(bool _arg) { this->m_IgnoreZeros = _arg; } bool QmitkImageStatisticsCalculationThread::GetIgnoreZeroValueVoxel() { return this->m_IgnoreZeros; } void QmitkImageStatisticsCalculationThread::SetHistogramBinSize(double size) { this->m_HistogramBinSize = size; - this->m_prioritizeNBinsOverBinSize = false; } double QmitkImageStatisticsCalculationThread::GetHistogramBinSize() const { return this->m_HistogramBinSize; } -void QmitkImageStatisticsCalculationThread::SetHistogramNBins(double size) -{ - this->m_nBinsForHistogramStatistics = size; - this->m_prioritizeNBinsOverBinSize = true; -} - -double QmitkImageStatisticsCalculationThread::GetHistogramNBins() const -{ - return this->m_nBinsForHistogramStatistics; -} - std::string QmitkImageStatisticsCalculationThread::GetLastErrorMessage() { return m_message; } QmitkImageStatisticsCalculationThread::HistogramType::Pointer QmitkImageStatisticsCalculationThread::GetTimeStepHistogram(unsigned int t) { if (t >= this->m_HistogramVector.size()) return nullptr; return this->m_HistogramVector[t]; } bool QmitkImageStatisticsCalculationThread::GetStatisticsChangedFlag() { return m_StatisticChanged; } bool QmitkImageStatisticsCalculationThread::GetStatisticsUpdateSuccessFlag() { return m_CalculationSuccessful; } void QmitkImageStatisticsCalculationThread::run() { bool statisticCalculationSuccessful = true; mitk::ImageStatisticsCalculator::Pointer calculator = mitk::ImageStatisticsCalculator::New(); if(this->m_StatisticsImage.IsNotNull()) { calculator->SetInputImage(m_StatisticsImage); } else { statisticCalculationSuccessful = false; } // Bug 13416 : The ImageStatistics::SetImageMask() method can throw exceptions, i.e. when the dimensionality // of the masked and input image differ, we need to catch them and mark the calculation as failed // the same holds for the ::SetPlanarFigure() try { if(this->m_BinaryMask.IsNotNull()) { mitk::ImageMaskGenerator::Pointer imgMask = mitk::ImageMaskGenerator::New(); imgMask->SetImageMask(m_BinaryMask); calculator->SetMask(imgMask.GetPointer()); } if(this->m_PlanarFigureMask.IsNotNull()) { mitk::PlanarFigureMaskGenerator::Pointer pfMaskGen = mitk::PlanarFigureMaskGenerator::New(); pfMaskGen->SetInputImage(m_StatisticsImage); pfMaskGen->SetPlanarFigure(m_PlanarFigureMask); calculator->SetMask(pfMaskGen.GetPointer()); } } catch (const mitk::Exception& e) { MITK_ERROR << "MITK Exception: " << e.what(); statisticCalculationSuccessful = false; } catch( const itk::ExceptionObject& e) { MITK_ERROR << "ITK Exception:" << e.what(); statisticCalculationSuccessful = false; } catch ( const std::runtime_error &e ) { MITK_ERROR<< "Runtime Exception: " << e.what(); statisticCalculationSuccessful = false; } catch ( const std::exception &e ) { MITK_ERROR<< "Standard Exception: " << e.what(); statisticCalculationSuccessful = false; } bool statisticChanged = false; if (this->m_IgnoreZeros) { mitk::IgnorePixelMaskGenerator::Pointer ignorePixelValueMaskGen = mitk::IgnorePixelMaskGenerator::New(); ignorePixelValueMaskGen->SetIgnoredPixelValue(0); ignorePixelValueMaskGen->SetInputImage(m_StatisticsImage); calculator->SetSecondaryMask(ignorePixelValueMaskGen.GetPointer()); } else { calculator->SetSecondaryMask(nullptr); } - if (m_UseDefaultNBins) - { - calculator->SetNBinsForHistogramStatistics(100); - } - else - { - if (!m_prioritizeNBinsOverBinSize) - { - calculator->SetBinSizeForHistogramStatistics(m_HistogramBinSize); - } - else - { - calculator->SetNBinsForHistogramStatistics(100); - } - } + calculator->SetBinSizeForHistogramStatistics(m_HistogramBinSize); //calculator->SetHistogramBinSize( m_HistogramBinSize ); //calculator->SetUseDefaultBinSize( m_UseDefaultBinSize ); for (unsigned int i = 0; i < m_StatisticsImage->GetTimeSteps(); i++) { try { calculator->GetStatistics(i); } catch ( mitk::Exception& e) { //m_message = e.GetDescription(); MITK_ERROR<< "MITK Exception: " << e.what(); statisticCalculationSuccessful = false; } catch ( const std::runtime_error &e ) { //m_message = "Failure: " + std::string(e.what()); MITK_ERROR<< "Runtime Exception: " << e.what(); statisticCalculationSuccessful = false; } catch ( const std::exception &e ) { //m_message = "Failure: " + std::string(e.what()); MITK_ERROR<< "Standard Exception: " << e.what(); statisticCalculationSuccessful = false; } } this->m_StatisticChanged = statisticChanged; this->m_CalculationSuccessful = statisticCalculationSuccessful; if(statisticCalculationSuccessful) { this->m_StatisticsVector.clear(); this->m_HistogramVector.clear(); for (unsigned int i = 0; i < m_StatisticsImage->GetTimeSteps(); i++) { this->m_StatisticsVector.push_back(calculator->GetStatistics(i)); this->m_HistogramVector.push_back((HistogramType*)this->m_StatisticsVector[i]->GetHistogram()); } } } diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsCalculationThread.h b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsCalculationThread.h index a18d6fd287..2e9ade1974 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsCalculationThread.h +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsCalculationThread.h @@ -1,123 +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. ===================================================================*/ #ifndef QMITKIMAGESTATISTICSCALCULATIONTHREAD_H_INCLUDED #define QMITKIMAGESTATISTICSCALCULATIONTHREAD_H_INCLUDED //QT headers #include #include //mitk headers #include "mitkImage.h" #include "mitkPlanarFigure.h" #include "mitkImageStatisticsCalculator.h" // itk headers #ifndef __itkHistogram_h #include #endif /** /brief This class is executed as background thread for image statistics calculation. * Documentation: This class is derived from QThread and is intended to be used by QmitkImageStatisticsView to run the image statistics calculation in a background thread keepung the gui usable. * \ingroup Plugins/MeasurementToolbox */ class QmitkImageStatisticsCalculationThread : public QThread { Q_OBJECT public: typedef itk::Statistics::Histogram HistogramType; /*! /brief standard constructor. */ QmitkImageStatisticsCalculationThread(); /*! /brief standard destructor. */ ~QmitkImageStatisticsCalculationThread(); - /*! - *\brief Automatically calculate bin size to obtain 200 bins. */ - void SetUseDefaultNBins(bool useDefault); + /*! /brief Initializes the object with necessary data. */ void Initialize( mitk::Image::Pointer image, mitk::Image::Pointer binaryImage, mitk::PlanarFigure::Pointer planarFig ); /*! /brief returns the calculated image statistics. */ std::vector GetStatisticsData(); /*! /brief */ mitk::Image::Pointer GetStatisticsImage(); /*! /brief Set the time step of the image you want to process. */ void SetTimeStep( int times ); /*! /brief Get the time step of the image you want to process. */ int GetTimeStep(); /*! /brief Set flag to ignore zero valued voxels */ void SetIgnoreZeroValueVoxel( bool _arg ); /*! /brief Get status of zero value voxel ignoring. */ bool GetIgnoreZeroValueVoxel(); /*! /brief Set bin size for histogram resolution.*/ void SetHistogramBinSize( double size); /*! /brief Get bin size for histogram resolution.*/ double GetHistogramBinSize() const; /*! - /brief Set bin size for histogram resolution.*/ - void SetHistogramNBins( double size); - /*! - /brief Get bin size for histogram resolution.*/ - double GetHistogramNBins() const; - /*! /brief Returns the histogram of the currently selected time step. */ HistogramType::Pointer GetTimeStepHistogram(unsigned int t = 0); /*! /brief Returns a flag indicating if the statistics have changed during calculation */ bool GetStatisticsChangedFlag(); /*! /brief Returns a flag the indicates if the statistics are updated successfully */ bool GetStatisticsUpdateSuccessFlag(); /*! /brief Method called once the thread is executed. */ void run() override; std::string GetLastErrorMessage(); private: //member declaration mitk::Image::Pointer m_StatisticsImage; ///< member variable holds the input image for which the statistics need to be calculated. mitk::Image::Pointer m_BinaryMask; ///< member variable holds the binary mask image for segmentation image statistics calculation. mitk::PlanarFigure::Pointer m_PlanarFigureMask; ///< member variable holds the planar figure for segmentation image statistics calculation. std::vector m_StatisticsVector; ///< member variable holds the result structs. int m_TimeStep; ///< member variable holds the time step for statistics calculation bool m_IgnoreZeros; ///< member variable holds flag to indicate if zero valued voxel should be suppressed double m_HistogramBinSize; ///< member variable holds the bin size for histogram resolution. bool m_StatisticChanged; ///< flag set if statistics have changed bool m_CalculationSuccessful; ///< flag set if statistics calculation was successful std::vector m_HistogramVector; ///< member holds the histograms of all time steps. std::string m_message; - bool m_UseDefaultNBins; - unsigned int m_nBinsForHistogramStatistics; - bool m_prioritizeNBinsOverBinSize; }; #endif // QMITKIMAGESTATISTICSCALCULATIONTHREAD_H_INCLUDED diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.cpp b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.cpp index e403667a1b..045a4bafcb 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.cpp +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.cpp @@ -1,1375 +1,1375 @@ /*=================================================================== 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 "QmitkImageStatisticsView.h" // Qt includes #include #include #include // berry includes #include // mitk includes #include "mitkNodePredicateDataType.h" #include "mitkNodePredicateOr.h" #include "mitkPlanarFigureInteractor.h" #include "mitkImageTimeSelector.h" #include #include // itk includes #include "itksys/SystemTools.hxx" #include #include "itkImageRegionConstIteratorWithIndex.h" #include //blueberry includes #include #include const std::string QmitkImageStatisticsView::VIEW_ID = "org.mitk.views.imagestatistics"; const int QmitkImageStatisticsView::STAT_TABLE_BASE_HEIGHT = 180; QmitkImageStatisticsView::QmitkImageStatisticsView(QObject* /*parent*/, const char* /*name*/) : m_Controls( nullptr ), m_TimeStepperAdapter( nullptr ), m_SelectedImage( nullptr ), m_SelectedImageMask( nullptr ), m_SelectedPlanarFigure( nullptr ), m_ImageObserverTag( -1 ), m_ImageMaskObserverTag( -1 ), m_PlanarFigureObserverTag( -1 ), m_TimeObserverTag( -1 ), m_CurrentStatisticsValid( false ), m_StatisticsUpdatePending( false ), m_DataNodeSelectionChanged ( false ), m_Visible(false) { this->m_CalculationThread = new QmitkImageStatisticsCalculationThread; } QmitkImageStatisticsView::~QmitkImageStatisticsView() { if ( m_SelectedImage != nullptr ) m_SelectedImage->RemoveObserver( m_ImageObserverTag ); if ( m_SelectedImageMask != nullptr ) m_SelectedImageMask->RemoveObserver( m_ImageMaskObserverTag ); if ( m_SelectedPlanarFigure != nullptr ) m_SelectedPlanarFigure->RemoveObserver( m_PlanarFigureObserverTag ); while(this->m_CalculationThread->isRunning()) // wait until thread has finished { itksys::SystemTools::Delay(100); } delete this->m_CalculationThread; } void QmitkImageStatisticsView::CreateQtPartControl(QWidget *parent) { if (m_Controls == nullptr) { m_Controls = new Ui::QmitkImageStatisticsViewControls; m_Controls->setupUi(parent); CreateConnections(); m_Controls->m_ErrorMessageLabel->hide(); m_Controls->m_StatisticsWidgetStack->setCurrentIndex(0); m_Controls->m_BinSizeFrame->setEnabled(false); } } void QmitkImageStatisticsView::OnPageSuccessfullyLoaded() { berry::IPreferencesService* prefService = berry::WorkbenchPlugin::GetDefault()->GetPreferencesService(); m_StylePref = prefService->GetSystemPreferences()->Node(berry::QtPreferences::QT_STYLES_NODE); QString styleName = m_StylePref->Get(berry::QtPreferences::QT_STYLE_NAME, ""); if (styleName == ":/org.blueberry.ui.qt/darkstyle.qss") { this->m_Controls->m_JSHistogram->SetTheme(QmitkChartWidget::ChartStyle::darkstyle); } else { this->m_Controls->m_JSHistogram->SetTheme(QmitkChartWidget::ChartStyle::lightstyle); } } void QmitkImageStatisticsView::CreateConnections() { if ( m_Controls ) { connect( (QObject*)(this->m_Controls->m_ButtonCopyHistogramToClipboard), SIGNAL(clicked()),(QObject*) this, SLOT(OnClipboardHistogramButtonClicked()) ); connect( (QObject*)(this->m_Controls->m_ButtonCopyStatisticsToClipboard), SIGNAL(clicked()),(QObject*) this, SLOT(OnClipboardStatisticsButtonClicked()) ); connect( (QObject*)(this->m_Controls->m_IgnoreZerosCheckbox), SIGNAL(clicked()),(QObject*) this, SLOT(OnIgnoreZerosCheckboxClicked()) ); connect( (QObject*) this->m_CalculationThread, SIGNAL(finished()),this, SLOT( OnThreadedStatisticsCalculationEnds()),Qt::QueuedConnection); connect( (QObject*) this, SIGNAL(StatisticsUpdate()),this, SLOT( RequestStatisticsUpdate()), Qt::QueuedConnection); connect( (QObject*) this->m_Controls->m_StatisticsTable, SIGNAL(cellDoubleClicked(int,int)),this, SLOT( JumpToCoordinates(int,int)) ); connect((QObject*)(this->m_Controls->m_barRadioButton), SIGNAL(clicked()), (QObject*)(this), SLOT(OnBarRadioButtonSelected())); connect((QObject*)(this->m_Controls->m_lineRadioButton), SIGNAL(clicked()), (QObject*)(this), SLOT(OnLineRadioButtonSelected())); connect( (QObject*) (this->m_Controls->m_HistogramBinSizeSpinbox), SIGNAL(editingFinished()), this, SLOT(OnHistogramBinSizeBoxValueChanged())); connect((QObject*)(this->m_Controls->m_UseDefaultBinSizeBox), SIGNAL(clicked()), (QObject*) this, SLOT(OnDefaultBinSizeBoxChanged())); connect((QObject*)(this->m_Controls->m_ShowSubchartCheckBox), SIGNAL(clicked()), (QObject*) this, SLOT(OnShowSubchartBoxChanged())); connect((QObject*)(this->m_Controls->m_JSHistogram), SIGNAL(PageSuccessfullyLoaded()), (QObject*) this, SLOT(OnPageSuccessfullyLoaded())); } } void QmitkImageStatisticsView::OnDefaultBinSizeBoxChanged() { m_Controls->m_BinSizeFrame->setEnabled(!m_Controls->m_UseDefaultBinSizeBox->isChecked()); if (m_CalculationThread != nullptr){ m_Controls->m_HistogramBinSizeSpinbox->setValue(m_CalculationThread->GetHistogramBinSize()); - m_CalculationThread->SetUseDefaultNBins(m_Controls->m_UseDefaultBinSizeBox->isChecked()); } this->UpdateStatistics(); } void QmitkImageStatisticsView::OnShowSubchartBoxChanged() { bool showSubchart = this->m_Controls->m_ShowSubchartCheckBox->isChecked(); this->m_Controls->m_JSHistogram->Reload(showSubchart); } void QmitkImageStatisticsView::OnBarRadioButtonSelected() { this->m_Controls->m_JSHistogram->SetChartTypeForAllDataAndReload(QmitkChartWidget::ChartType::bar); } void QmitkImageStatisticsView::OnLineRadioButtonSelected() { this->m_Controls->m_JSHistogram->SetChartTypeForAllDataAndReload(QmitkChartWidget::ChartType::line); } void QmitkImageStatisticsView::PartClosed(const berry::IWorkbenchPartReference::Pointer& ) { } void QmitkImageStatisticsView::OnTimeChanged(const itk::EventObject& e) { if (this->m_SelectedDataNodes.isEmpty() || this->m_SelectedImage == nullptr) return; const mitk::SliceNavigationController::GeometryTimeEvent* timeEvent = dynamic_cast(&e); assert(timeEvent != nullptr); int timestep = timeEvent->GetPos(); if (this->m_SelectedImage->GetTimeSteps() > 1) { for (int x = 0; x < this->m_Controls->m_StatisticsTable->columnCount(); x++) { for (int y = 0; y < this->m_Controls->m_StatisticsTable->rowCount(); y++) { QTableWidgetItem* item = this->m_Controls->m_StatisticsTable->item(y, x); if (item == nullptr) break; if (x == timestep) { item->setBackgroundColor(Qt::yellow); } else { if (y % 2 == 0) item->setBackground(this->m_Controls->m_StatisticsTable->palette().base()); else item->setBackground(this->m_Controls->m_StatisticsTable->palette().alternateBase()); } } } this->m_Controls->m_StatisticsTable->viewport()->update(); } if ((this->m_SelectedImage->GetTimeSteps() == 1 && timestep == 0) || this->m_SelectedImage->GetTimeSteps() > 1) { // display histogram for selected timestep this->m_Controls->m_JSHistogram->Clear(); QmitkImageStatisticsCalculationThread::HistogramType::ConstPointer histogram = (QmitkImageStatisticsCalculationThread::HistogramType::ConstPointer)this->m_CalculationThread->GetTimeStepHistogram(timestep); if (histogram.IsNotNull()) { bool closedFigure = this->m_CalculationThread->GetStatisticsUpdateSuccessFlag(); if (closedFigure) { auto imageNameLabel = m_Controls->m_SelectedFeatureImageLabel->text().toStdString(); this->m_Controls->m_JSHistogram->AddData2D(ConvertHistogramToMap(histogram), imageNameLabel); if (this->m_Controls->m_lineRadioButton->isChecked()) { this->m_Controls->m_JSHistogram->SetChartType(imageNameLabel, QmitkChartWidget::ChartType::line); } else { this->m_Controls->m_JSHistogram->SetChartType(imageNameLabel, QmitkChartWidget::ChartType::bar); } this->m_Controls->m_JSHistogram->SetXAxisLabel("Grey value"); this->m_Controls->m_JSHistogram->SetYAxisLabel("Frequency"); this->m_Controls->m_JSHistogram->Show(this->m_Controls->m_ShowSubchartCheckBox->isChecked()); } } } } void QmitkImageStatisticsView::JumpToCoordinates(int row ,int col) { if(m_SelectedDataNodes.isEmpty()) { MITK_WARN("QmitkImageStatisticsView") << "No data node selected for statistics calculation." ; return; } mitk::Point3D world; if (row==5 && !m_WorldMinList.empty()) world = m_WorldMinList[col]; else if (row==4 && !m_WorldMaxList.empty()) world = m_WorldMaxList[col]; else return; mitk::IRenderWindowPart* part = this->GetRenderWindowPart(); if (part) { part->GetQmitkRenderWindow("axial")->GetSliceNavigationController()->SelectSliceByPoint(world); part->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()->SelectSliceByPoint(world); part->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()->SelectSliceByPoint(world); mitk::SliceNavigationController::GeometryTimeEvent timeEvent(this->m_SelectedImage->GetTimeGeometry(), col); part->GetQmitkRenderWindow("axial")->GetSliceNavigationController()->SetGeometryTime(timeEvent); } } void QmitkImageStatisticsView::OnIgnoreZerosCheckboxClicked() { emit StatisticsUpdate(); } void QmitkImageStatisticsView::OnClipboardHistogramButtonClicked() { if ( m_CurrentStatisticsValid && !( m_SelectedPlanarFigure != nullptr)) { const unsigned int t = this->GetRenderWindowPart()->GetTimeNavigationController()->GetTime()->GetPos(); typedef mitk::ImageStatisticsCalculator::HistogramType HistogramType; const HistogramType *histogram = this->m_CalculationThread->GetTimeStepHistogram(t).GetPointer(); QString clipboard( "Measurement \t Frequency\n" ); for ( HistogramType::ConstIterator it = histogram->Begin(); it != histogram->End(); ++it ) { if( m_Controls->m_HistogramBinSizeSpinbox->value() == 1.0) { clipboard = clipboard.append( "%L1 \t %L2\n" ) .arg( it.GetMeasurementVector()[0], 0, 'f', 0 ) .arg( it.GetFrequency() ); } else { clipboard = clipboard.append( "%L1 \t %L2\n" ) .arg( it.GetMeasurementVector()[0], 0, 'f', 2 ) .arg( it.GetFrequency() ); } } QApplication::clipboard()->setText( clipboard, QClipboard::Clipboard ); } // If a (non-closed) PlanarFigure is selected, display a line profile widget else if ( m_CurrentStatisticsValid && (m_SelectedPlanarFigure != nullptr )) { /*auto intensity = m_Controls->m_JSHistogram->GetFrequency(); auto pixel = m_Controls->m_JSHistogram->GetMeasurement(); QString clipboard( "Pixel \t Intensity\n" ); auto j = pixel.begin(); for (auto i = intensity.begin(); i < intensity.end(); i++) { assert(j != pixel.end()); clipboard = clipboard.append( "%L1 \t %L2\n" ) .arg( (*j).toString()) .arg( (*i).toString()); j++; } QApplication::clipboard()->setText( clipboard, QClipboard::Clipboard ); */ } else { QApplication::clipboard()->clear(); } } void QmitkImageStatisticsView::OnClipboardStatisticsButtonClicked() { QLocale tempLocal; QLocale::setDefault(QLocale(QLocale::English, QLocale::UnitedStates)); if ( m_CurrentStatisticsValid && !( m_SelectedPlanarFigure != nullptr)) { const std::vector &statistics = this->m_CalculationThread->GetStatisticsData(); // Set time borders for for loop ;) unsigned int startT, endT; if(this->m_Controls->m_CheckBox4dCompleteTable->checkState()==Qt::CheckState::Unchecked) { startT = this->GetRenderWindowPart()->GetTimeNavigationController()->GetTime()-> GetPos(); endT = startT+1; } else { startT = 0; endT = statistics.size(); } QVector< QVector > statisticsTable; QStringList headline; // Create Headline headline << " " << "Mean" << "Median" << "StdDev" << "RMS" << "Max" << "Min" << "NumberOfVoxels" << "Skewness" << "Kurtosis" << "Uniformity" << "Entropy" << "MPP" << "UPP" << "V [mm³]"; for(int i=0;i row; row.append(headline.at(i)); statisticsTable.append(row); } // Fill Table for(unsigned int t=startT;tGetMean()) << QString::number(statistics[t]->GetMedian()) << QString::number(statistics[t]->GetStd()) << QString::number(statistics[t]->GetRMS()) << QString::number(statistics[t]->GetMax()) << QString::number(statistics[t]->GetMin()) << QString::number(statistics[t]->GetN()) << QString::number(statistics[t]->GetSkewness()) << QString::number(statistics[t]->GetKurtosis()) << QString::number(statistics[t]->GetUniformity()) << QString::number(statistics[t]->GetEntropy()) << QString::number(statistics[t]->GetMPP()) << QString::number(statistics[t]->GetUPP()) << QString::number(m_Controls->m_StatisticsTable->item(7, 0)->data(Qt::DisplayRole).toDouble()); for(int z=0;zsetText(clipboard, QClipboard::Clipboard); } else { QApplication::clipboard()->clear(); } QLocale::setDefault(tempLocal); } void QmitkImageStatisticsView::OnSelectionChanged( berry::IWorkbenchPart::Pointer /*part*/, const QList &nodes ) { if (this->m_Visible) { this->SelectionChanged( nodes ); } else { this->m_DataNodeSelectionChanged = true; } } void QmitkImageStatisticsView::SelectionChanged(const QList &selectedNodes) { //Clear Histogram if data node is deselected m_Controls->m_JSHistogram->Clear(); if( this->m_StatisticsUpdatePending ) { this->m_DataNodeSelectionChanged = true; return; // not ready for new data now! } if (selectedNodes.size() == this->m_SelectedDataNodes.size()) { int i = 0; for (; i < selectedNodes.size(); ++i) { if (selectedNodes.at(i) != this->m_SelectedDataNodes.at(i)) { break; } } // node selection did not change if (i == selectedNodes.size()) return; } //reset the feature image and image mask field m_Controls->m_SelectedFeatureImageLabel->setText("None"); m_Controls->m_SelectedMaskLabel->setText("None"); this->ReinitData(); if (selectedNodes.isEmpty()) { m_Controls->m_lineRadioButton->setEnabled(true); m_Controls->m_barRadioButton->setEnabled(true); m_Controls->m_HistogramBinSizeSpinbox->setEnabled(true); m_Controls->m_HistogramBinSizeCaptionLabel->setEnabled(true); m_Controls->m_UseDefaultBinSizeBox->setEnabled(true); m_Controls->m_InfoLabel->setText(""); m_Controls->groupBox->setEnabled(false); m_Controls->groupBox_3->setEnabled(false); } else { m_Controls->groupBox->setEnabled(true); m_Controls->groupBox_3->setEnabled(true); m_Controls->m_barRadioButton->setChecked(true); } if(selectedNodes.size() == 1 || selectedNodes.size() == 2) { bool isBinary = false; selectedNodes.value(0)->GetBoolProperty("binary",isBinary); mitk::NodePredicateDataType::Pointer isLabelSet = mitk::NodePredicateDataType::New("LabelSetImage"); isBinary |= isLabelSet->CheckNode(selectedNodes.value(0)); if(isBinary) { m_Controls->m_lineRadioButton->setEnabled(true); m_Controls->m_barRadioButton->setEnabled(true); m_Controls->m_HistogramBinSizeSpinbox->setEnabled(true); m_Controls->m_HistogramBinSizeCaptionLabel->setEnabled(true); m_Controls->m_UseDefaultBinSizeBox->setEnabled(true); m_Controls->m_InfoLabel->setText(""); } for (int i= 0; i< selectedNodes.size(); ++i) { this->m_SelectedDataNodes.push_back(selectedNodes.at(i)); } this->m_DataNodeSelectionChanged = false; this->m_Controls->m_ErrorMessageLabel->setText( "" ); this->m_Controls->m_ErrorMessageLabel->hide(); emit StatisticsUpdate(); } else { this->m_DataNodeSelectionChanged = false; } } void QmitkImageStatisticsView::ReinitData() { while( this->m_CalculationThread->isRunning()) // wait until thread has finished { itksys::SystemTools::Delay(100); } if(this->m_SelectedImage != nullptr) { this->m_SelectedImage->RemoveObserver( this->m_ImageObserverTag); this->m_SelectedImage = nullptr; } if(this->m_SelectedImageMask != nullptr) { this->m_SelectedImageMask->RemoveObserver( this->m_ImageMaskObserverTag); this->m_SelectedImageMask = nullptr; } if(this->m_SelectedPlanarFigure != nullptr) { this->m_SelectedPlanarFigure->RemoveObserver( this->m_PlanarFigureObserverTag); this->m_SelectedPlanarFigure = nullptr; } this->m_SelectedDataNodes.clear(); this->m_StatisticsUpdatePending = false; m_Controls->m_ErrorMessageLabel->setText( "" ); m_Controls->m_ErrorMessageLabel->hide(); this->InvalidateStatisticsTableView(); m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 0 ); } void QmitkImageStatisticsView::OnThreadedStatisticsCalculationEnds() { std::stringstream message; message << ""; m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() ); m_Controls->m_ErrorMessageLabel->hide(); this->WriteStatisticsToGUI(); } void QmitkImageStatisticsView::UpdateStatistics() { mitk::IRenderWindowPart* renderPart = this->GetRenderWindowPart(); if ( renderPart == nullptr ) { this->m_StatisticsUpdatePending = false; return; } m_WorldMinList.clear(); m_WorldMaxList.clear(); // classify selected nodes mitk::NodePredicateDataType::Pointer isImage = mitk::NodePredicateDataType::New("Image"); mitk::NodePredicateDataType::Pointer isLabelSet = mitk::NodePredicateDataType::New("LabelSetImage"); mitk::NodePredicateOr::Pointer imagePredicate = mitk::NodePredicateOr::New(isImage, isLabelSet); std::string maskName; std::string maskType; std::string featureImageName; unsigned int maskDimension = 0; // reset data from last run ITKCommandType::Pointer changeListener = ITKCommandType::New(); changeListener->SetCallbackFunction( this, &QmitkImageStatisticsView::SelectedDataModified ); mitk::DataNode::Pointer planarFigureNode; for( int i= 0 ; i < this->m_SelectedDataNodes.size(); ++i) { mitk::PlanarFigure::Pointer planarFig = dynamic_cast(this->m_SelectedDataNodes.at(i)->GetData()); if( imagePredicate->CheckNode(this->m_SelectedDataNodes.at(i)) ) { bool isMask = false; this->m_SelectedDataNodes.at(i)->GetPropertyValue("binary", isMask); isMask |= isLabelSet->CheckNode(this->m_SelectedDataNodes.at(i)); if( this->m_SelectedImageMask == nullptr && isMask) { this->m_SelectedImageMask = dynamic_cast(this->m_SelectedDataNodes.at(i)->GetData()); this->m_ImageMaskObserverTag = this->m_SelectedImageMask->AddObserver(itk::ModifiedEvent(), changeListener); maskName = this->m_SelectedDataNodes.at(i)->GetName(); maskType = m_SelectedImageMask->GetNameOfClass(); maskDimension = 3; } else if( !isMask ) { if(this->m_SelectedImage == nullptr) { this->m_SelectedImage = static_cast(this->m_SelectedDataNodes.at(i)->GetData()); this->m_ImageObserverTag = this->m_SelectedImage->AddObserver(itk::ModifiedEvent(), changeListener); } featureImageName = this->m_SelectedDataNodes.at(i)->GetName(); } } else if (planarFig.IsNotNull()) { if(this->m_SelectedPlanarFigure == nullptr) { this->m_SelectedPlanarFigure = planarFig; this->m_PlanarFigureObserverTag = this->m_SelectedPlanarFigure->AddObserver(mitk::EndInteractionPlanarFigureEvent(), changeListener); maskName = this->m_SelectedDataNodes.at(i)->GetName(); maskType = this->m_SelectedPlanarFigure->GetNameOfClass(); maskDimension = 2; planarFigureNode = m_SelectedDataNodes.at(i); } } else { std::stringstream message; message << "" << "Invalid data node type!" << ""; m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() ); m_Controls->m_ErrorMessageLabel->show(); } } if(maskName == "") { maskName = "None"; maskType = ""; maskDimension = 0; } if(featureImageName == "") { featureImageName = "None"; } if (m_SelectedPlanarFigure != nullptr && m_SelectedImage == nullptr) { mitk::DataStorage::SetOfObjects::ConstPointer parentSet = this->GetDataStorage()->GetSources(planarFigureNode); for (unsigned int i=0; iSize(); i++) { mitk::DataNode::Pointer node = parentSet->ElementAt(i); if( imagePredicate->CheckNode(node) ) { bool isMask = false; node->GetPropertyValue("binary", isMask); isMask |= isLabelSet->CheckNode(node); if( !isMask ) { if(this->m_SelectedImage == nullptr) { this->m_SelectedImage = static_cast(node->GetData()); this->m_ImageObserverTag = this->m_SelectedImage->AddObserver(itk::ModifiedEvent(), changeListener); } } } } } unsigned int timeStep = renderPart->GetTimeNavigationController()->GetTime()->GetPos(); if ( m_SelectedImage != nullptr && m_SelectedImage->IsInitialized()) { // Check if a the selected image is a multi-channel image. If yes, statistics // cannot be calculated currently. if ( m_SelectedImage->GetPixelType().GetNumberOfComponents() > 1 ) { std::stringstream message; message << "Multi-component images not supported."; m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() ); m_Controls->m_ErrorMessageLabel->show(); this->InvalidateStatisticsTableView(); m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 0 ); m_CurrentStatisticsValid = false; this->m_StatisticsUpdatePending = false; m_Controls->m_lineRadioButton->setEnabled(true); m_Controls->m_barRadioButton->setEnabled(true); m_Controls->m_HistogramBinSizeSpinbox->setEnabled(true); m_Controls->m_HistogramBinSizeCaptionLabel->setEnabled(true); m_Controls->m_UseDefaultBinSizeBox->setEnabled(true); m_Controls->m_InfoLabel->setText(""); return; } std::stringstream maskLabel; maskLabel << maskName; if ( maskDimension > 0 ) { maskLabel << " [" << maskDimension << "D " << maskType << "]"; } m_Controls->m_SelectedMaskLabel->setText( maskLabel.str().c_str() ); m_Controls->m_SelectedFeatureImageLabel->setText(featureImageName.c_str()); // check time step validity if(m_SelectedImage->GetDimension() <= 3 && timeStep > m_SelectedImage->GetDimension(3)-1) { timeStep = m_SelectedImage->GetDimension(3)-1; } // Add the used mask time step to the mask label so the user knows which mask time step was used // if the image time step is bigger than the total number of mask time steps (see // ImageStatisticsCalculator::ExtractImageAndMask) if (m_SelectedImageMask != nullptr) { unsigned int maskTimeStep = timeStep; if (maskTimeStep >= m_SelectedImageMask->GetTimeSteps()) { maskTimeStep = m_SelectedImageMask->GetTimeSteps() - 1; } m_Controls->m_SelectedMaskLabel->setText(m_Controls->m_SelectedMaskLabel->text() + QString(" (t=") + QString::number(maskTimeStep) + QString(")")); } // check if the segmentation mask is empty if (m_SelectedImageMask != NULL) { typedef itk::Image ItkImageType; typedef itk::ImageRegionConstIteratorWithIndex< ItkImageType > IteratorType; ItkImageType::Pointer itkImage; mitk::CastToItkImage( m_SelectedImageMask, itkImage ); bool empty = true; IteratorType it( itkImage, itkImage->GetLargestPossibleRegion() ); while ( !it.IsAtEnd() ) { ItkImageType::ValueType val = it.Get(); if ( val != 0 ) { empty = false; break; } ++it; } if ( empty ) { std::stringstream message; message << "Empty segmentation mask selected..."; m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() ); m_Controls->m_ErrorMessageLabel->show(); return; } } //// initialize thread and trigger it this->m_CalculationThread->SetIgnoreZeroValueVoxel( m_Controls->m_IgnoreZerosCheckbox->isChecked() ); this->m_CalculationThread->Initialize( m_SelectedImage, m_SelectedImageMask, m_SelectedPlanarFigure ); this->m_CalculationThread->SetTimeStep( timeStep ); std::stringstream message; message << "Calculating statistics..."; m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() ); m_Controls->m_ErrorMessageLabel->show(); try { // Compute statistics // this->m_CalculationThread->SetUseDefaultBinSize(m_Controls->m_UseDefaultBinSizeBox->isChecked()); this->m_CalculationThread->start(); } catch ( const mitk::Exception& e) { std::stringstream message; message << "" << e.GetDescription() << ""; m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() ); m_Controls->m_ErrorMessageLabel->show(); this->m_StatisticsUpdatePending = false; } catch ( const std::runtime_error &e ) { // In case of exception, print error message on GUI std::stringstream message; message << "" << e.what() << ""; m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() ); m_Controls->m_ErrorMessageLabel->show(); this->m_StatisticsUpdatePending = false; } catch ( const std::exception &e ) { MITK_ERROR << "Caught exception: " << e.what(); // In case of exception, print error message on GUI std::stringstream message; message << "Error! Unequal Dimensions of Image and Segmentation. No recompute possible "; m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() ); m_Controls->m_ErrorMessageLabel->show(); this->m_StatisticsUpdatePending = false; } AdaptBinSizeCheckboxStepsize(m_SelectedImage); } else { this->m_StatisticsUpdatePending = false; } } void QmitkImageStatisticsView::SelectedDataModified() { if( !m_StatisticsUpdatePending ) { emit StatisticsUpdate(); } } void QmitkImageStatisticsView::NodeRemoved(const mitk::DataNode *node) { while(this->m_CalculationThread->isRunning()) // wait until thread has finished { itksys::SystemTools::Delay(100); } if (node->GetData() == m_SelectedImage) { m_SelectedImage = nullptr; } } void QmitkImageStatisticsView::RequestStatisticsUpdate() { if ( !m_StatisticsUpdatePending ) { if(this->m_DataNodeSelectionChanged) { this->SelectionChanged(this->GetCurrentSelection()); } else { this->m_StatisticsUpdatePending = true; this->UpdateStatistics(); } } if (this->GetRenderWindowPart()) this->GetRenderWindowPart()->RequestUpdate(); } void QmitkImageStatisticsView::OnHistogramBinSizeBoxValueChanged() { if (m_Controls->m_HistogramBinSizeSpinbox->value() != m_HistogramBinSize) { m_HistogramBinSize = m_Controls->m_HistogramBinSizeSpinbox->value(); this->m_CalculationThread->SetHistogramBinSize(m_Controls->m_HistogramBinSizeSpinbox->value()); this->UpdateStatistics(); } } void QmitkImageStatisticsView::WriteStatisticsToGUI() { m_Controls->m_JSHistogram->Clear(); //Disconnect OnLineRadioButtonSelected() to prevent reloading chart when radiobutton is checked programmatically disconnect((QObject*)(this->m_Controls->m_JSHistogram), SIGNAL(PageSuccessfullyLoaded()), 0, 0); connect((QObject*)(this->m_Controls->m_JSHistogram), SIGNAL(PageSuccessfullyLoaded()), (QObject*) this, SLOT(OnPageSuccessfullyLoaded())); m_Controls->m_lineRadioButton->setEnabled(true); m_Controls->m_barRadioButton->setEnabled(true); m_Controls->m_HistogramBinSizeSpinbox->setEnabled(true); m_Controls->m_HistogramBinSizeCaptionLabel->setEnabled(true); m_Controls->m_InfoLabel->setText(""); if (m_DataNodeSelectionChanged) { this->m_StatisticsUpdatePending = false; this->RequestStatisticsUpdate(); return; // stop visualization of results and calculate statistics of new selection } if (this->m_CalculationThread->GetStatisticsUpdateSuccessFlag()) { if (this->m_CalculationThread->GetStatisticsChangedFlag()) { // Do not show any error messages m_Controls->m_ErrorMessageLabel->hide(); m_CurrentStatisticsValid = true; } if (m_SelectedImage != nullptr) { //all statistics are now computed also on planar figures (lines, paths...)! // If a (non-closed) PlanarFigure is selected, display a line profile widget if (m_SelectedPlanarFigure != nullptr) { // Check if the (closed) planar figure is out of bounds and so no image mask could be calculated--> Intensity Profile can not be calculated bool outOfBounds = false; if (m_SelectedPlanarFigure->IsClosed() && m_SelectedImageMask == nullptr) { outOfBounds = true; const QString message("Planar figure is on a rotated image plane or outside the image bounds."); m_Controls->m_InfoLabel->setText(message); } // check whether PlanarFigure is initialized const mitk::PlaneGeometry *planarFigurePlaneGeometry = m_SelectedPlanarFigure->GetPlaneGeometry(); if (!(planarFigurePlaneGeometry == nullptr || outOfBounds)) { unsigned int timeStep = this->GetRenderWindowPart()->GetTimeNavigationController()->GetTime()->GetPos(); mitk::Image::Pointer image; if (this->m_CalculationThread->GetStatisticsImage()->GetDimension() == 4) { mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); timeSelector->SetInput(this->m_CalculationThread->GetStatisticsImage()); timeSelector->SetTimeNr(timeStep); timeSelector->Update(); image = timeSelector->GetOutput(); } else { image = this->m_CalculationThread->GetStatisticsImage(); } mitk::IntensityProfile::ConstPointer intensityProfile = (mitk::IntensityProfile::ConstPointer)mitk::ComputeIntensityProfile(image, m_SelectedPlanarFigure); auto intensityProfileList = ConvertIntensityProfileToVector(intensityProfile); auto lineDataLabel = "Intensity profile " + m_Controls->m_SelectedMaskLabel->text().toStdString(); m_Controls->m_JSHistogram->SetChartType(lineDataLabel, QmitkChartWidget::ChartType::line); m_Controls->m_JSHistogram->AddData1D(intensityProfileList, lineDataLabel); m_Controls->m_JSHistogram->SetXAxisLabel("Distance"); m_Controls->m_JSHistogram->SetYAxisLabel("Intensity"); m_Controls->m_JSHistogram->Show(m_Controls->m_ShowSubchartCheckBox->isChecked()); m_Controls->m_lineRadioButton->setChecked(true); m_Controls->m_lineRadioButton->setEnabled(false); m_Controls->m_barRadioButton->setEnabled(false); m_Controls->m_HistogramBinSizeSpinbox->setEnabled(false); m_Controls->m_HistogramBinSizeCaptionLabel->setEnabled(false); m_Controls->m_UseDefaultBinSizeBox->setEnabled(false); //Reconnect OnLineRadioButtonSelected() connect((QObject*)(this->m_Controls->m_JSHistogram), SIGNAL(PageSuccessfullyLoaded()), (QObject*) this, SLOT(OnLineRadioButtonSelected())); auto statisticsVector = this->m_CalculationThread->GetStatisticsData(); //only one entry (current timestep) this->FillLinearProfileStatisticsTableView(statisticsVector.front().GetPointer(), this->m_CalculationThread->GetStatisticsImage()); QString message("Only linegraph available for an intensity profile!"); if (this->m_CalculationThread->GetStatisticsImage()->GetDimension() == 4) { message += "Only current timestep displayed!"; } message += ""; m_Controls->m_InfoLabel->setText(message); m_CurrentStatisticsValid = true; } else { // Clear statistics, histogram, and GUI this->InvalidateStatisticsTableView(); m_Controls->m_StatisticsWidgetStack->setCurrentIndex(0); m_CurrentStatisticsValid = false; m_Controls->m_ErrorMessageLabel->hide(); m_Controls->m_SelectedMaskLabel->setText("None"); this->m_StatisticsUpdatePending = false; m_Controls->m_lineRadioButton->setEnabled(true); m_Controls->m_barRadioButton->setEnabled(true); m_Controls->m_HistogramBinSizeSpinbox->setEnabled(true); m_Controls->m_HistogramBinSizeCaptionLabel->setEnabled(true); if (!outOfBounds) m_Controls->m_InfoLabel->setText(""); return; } } else { m_Controls->m_StatisticsWidgetStack->setCurrentIndex(0); + m_Controls->m_HistogramBinSizeSpinbox->setValue(this->m_CalculationThread->GetHistogramBinSize()); auto histogram = this->m_CalculationThread->GetTimeStepHistogram(this->m_CalculationThread->GetTimeStep()).GetPointer(); auto imageLabelName = m_Controls->m_SelectedFeatureImageLabel->text().toStdString(); m_Controls->m_JSHistogram->AddData2D(ConvertHistogramToMap(histogram), imageLabelName); m_Controls->m_JSHistogram->SetChartType(imageLabelName, QmitkChartWidget::ChartType::bar); this->m_Controls->m_JSHistogram->SetXAxisLabel("Gray value"); this->m_Controls->m_JSHistogram->SetYAxisLabel("Frequency"); m_Controls->m_UseDefaultBinSizeBox->setEnabled(true); m_Controls->m_JSHistogram->Show(this->m_Controls->m_ShowSubchartCheckBox->isChecked()); auto currentTime = this->GetRenderWindowPart()->GetTimeNavigationController()->GetTime()->GetPos(); this->AdaptBinSizeCheckBoxMinMax((this->m_CalculationThread->GetStatisticsData()).at(currentTime).GetPointer(), this->m_CalculationThread->GetStatisticsImage()->GetPixelType().GetComponentType()); this->FillStatisticsTableView(this->m_CalculationThread->GetStatisticsData(), this->m_CalculationThread->GetStatisticsImage()); } m_CurrentStatisticsValid = true; } } else { m_Controls->m_SelectedMaskLabel->setText("None"); m_Controls->m_ErrorMessageLabel->setText(m_CalculationThread->GetLastErrorMessage().c_str()); m_Controls->m_ErrorMessageLabel->show(); // Clear statistics and histogram this->InvalidateStatisticsTableView(); m_Controls->m_StatisticsWidgetStack->setCurrentIndex(0); m_CurrentStatisticsValid = false; } berry::IPreferencesService* prefService = berry::WorkbenchPlugin::GetDefault()->GetPreferencesService(); m_StylePref = prefService->GetSystemPreferences()->Node(berry::QtPreferences::QT_STYLES_NODE); this->m_StatisticsUpdatePending = false; } void QmitkImageStatisticsView::FillStatisticsTableView( const std::vector &statistics, const mitk::Image *image ) { this->m_Controls->m_StatisticsTable->setColumnCount(image->GetTimeSteps()); this->m_Controls->m_StatisticsTable->horizontalHeader()->setVisible(image->GetTimeSteps() > 1); // Set Checkbox for complete copy of statistic table if(image->GetTimeSteps()>1) { this->m_Controls->m_CheckBox4dCompleteTable->setEnabled(true); } else { this->m_Controls->m_CheckBox4dCompleteTable->setEnabled(false); this->m_Controls->m_CheckBox4dCompleteTable->setChecked(false); } for (unsigned int t = 0; t < image->GetTimeSteps(); t++) { this->m_Controls->m_StatisticsTable->setHorizontalHeaderItem(t, new QTableWidgetItem(QString::number(t))); if (statistics.at(t)->GetMaxIndex().size()==3) { mitk::Point3D index, max, min; index[0] = statistics.at(t)->GetMaxIndex()[0]; index[1] = statistics.at(t)->GetMaxIndex()[1]; index[2] = statistics.at(t)->GetMaxIndex()[2]; m_SelectedImage->GetGeometry()->IndexToWorld(index, max); this->m_WorldMaxList.push_back(max); index[0] = statistics.at(t)->GetMinIndex()[0]; index[1] = statistics.at(t)->GetMinIndex()[1]; index[2] = statistics.at(t)->GetMinIndex()[2]; m_SelectedImage->GetGeometry()->IndexToWorld(index, min); this->m_WorldMinList.push_back(min); } auto statisticsVector = AssembleStatisticsIntoVector(statistics.at(t).GetPointer(), image); unsigned int count = 0; for (const auto& entry : statisticsVector) { auto item = new QTableWidgetItem(entry); this->m_Controls->m_StatisticsTable->setItem(count, t, item); count++; } } this->m_Controls->m_StatisticsTable->resizeColumnsToContents(); int height = STAT_TABLE_BASE_HEIGHT; if (this->m_Controls->m_StatisticsTable->horizontalHeader()->isVisible()) height += this->m_Controls->m_StatisticsTable->horizontalHeader()->height(); if (this->m_Controls->m_StatisticsTable->horizontalScrollBar()->isVisible()) height += this->m_Controls->m_StatisticsTable->horizontalScrollBar()->height(); this->m_Controls->m_StatisticsTable->setMinimumHeight(height); // make sure the current timestep's column is highlighted (and the correct histogram is displayed) unsigned int t = this->GetRenderWindowPart()->GetTimeNavigationController()->GetTime()-> GetPos(); mitk::SliceNavigationController::GeometryTimeEvent timeEvent(this->m_SelectedImage->GetTimeGeometry(), t); this->OnTimeChanged(timeEvent); t = std::min(image->GetTimeSteps() - 1, t); // See bug 18340 /*QString hotspotMean; hotspotMean.append(QString("%1").arg(s[t].GetHotspotStatistics().GetMean(), 0, 'f', decimals)); hotspotMean += " ("; for (int i=0; im_Controls->m_StatisticsTable->setItem( 7, t, new QTableWidgetItem( hotspotMean ) ); QString hotspotMax; hotspotMax.append(QString("%1").arg(s[t].GetHotspotStatistics().GetMax(), 0, 'f', decimals)); hotspotMax += " ("; for (int i=0; im_Controls->m_StatisticsTable->setItem( 8, t, new QTableWidgetItem( hotspotMax ) ); QString hotspotMin; hotspotMin.append(QString("%1").arg(s[t].GetHotspotStatistics().GetMin(), 0, 'f', decimals)); hotspotMin += " ("; for (int i=0; im_Controls->m_StatisticsTable->setItem( 9, t, new QTableWidgetItem( hotspotMin ) );*/ } std::vector QmitkImageStatisticsView::AssembleStatisticsIntoVector(mitk::ImageStatisticsCalculator::StatisticsContainer::ConstPointer statistics, mitk::Image::ConstPointer image, bool noVolumeDefined) const { std::vector result; unsigned int decimals = 2; //statistics of higher order should have 5 decimal places because they used to be very small unsigned int decimalsHigherOrderStatistics = 5; if (image->GetPixelType().GetComponentType() == itk::ImageIOBase::DOUBLE || image->GetPixelType().GetComponentType() == itk::ImageIOBase::FLOAT) { decimals = 5; } result.push_back(GetFormattedString(statistics->GetMean(), decimals)); result.push_back(GetFormattedString(statistics->GetMedian(), decimals)); result.push_back(GetFormattedString(statistics->GetStd(), decimals)); result.push_back(GetFormattedString(statistics->GetRMS(), decimals)); result.push_back(GetFormattedString(statistics->GetMax(), decimals) + " " + GetFormattedIndex(statistics->GetMaxIndex())); result.push_back(GetFormattedString(statistics->GetMin(), decimals) + " " + GetFormattedIndex(statistics->GetMinIndex())); //to prevent large negative values of empty image statistics if (statistics->GetN() != std::numeric_limits::min()) { result.push_back(GetFormattedString(statistics->GetN(), 0)); const mitk::BaseGeometry *geometry = image->GetGeometry(); if (geometry != NULL && !noVolumeDefined) { const mitk::Vector3D &spacing = image->GetGeometry()->GetSpacing(); double volume = spacing[0] * spacing[1] * spacing[2] * static_cast(statistics->GetN()); result.push_back(GetFormattedString(volume, decimals)); } else { result.push_back("NA"); } } else { result.push_back("NA"); result.push_back("NA"); } result.push_back(GetFormattedString(statistics->GetSkewness(), decimalsHigherOrderStatistics)); result.push_back(GetFormattedString(statistics->GetKurtosis(), decimalsHigherOrderStatistics)); result.push_back(GetFormattedString(statistics->GetUniformity(), decimalsHigherOrderStatistics)); result.push_back(GetFormattedString(statistics->GetEntropy(), decimalsHigherOrderStatistics)); result.push_back(GetFormattedString(statistics->GetMPP(), decimals)); result.push_back(GetFormattedString(statistics->GetUPP(), decimalsHigherOrderStatistics)); return result; } void QmitkImageStatisticsView::FillLinearProfileStatisticsTableView(mitk::ImageStatisticsCalculator::StatisticsContainer::ConstPointer statistics, const mitk::Image *image) { this->m_Controls->m_StatisticsTable->setColumnCount(1); this->m_Controls->m_StatisticsTable->horizontalHeader()->setVisible(false); m_PlanarFigureStatistics = this->AssembleStatisticsIntoVector(statistics, image, true); for (unsigned int i = 0; i< m_PlanarFigureStatistics.size(); i++) { this->m_Controls->m_StatisticsTable->setItem( i, 0, new QTableWidgetItem(m_PlanarFigureStatistics[i] )); } this->m_Controls->m_StatisticsTable->resizeColumnsToContents(); int height = STAT_TABLE_BASE_HEIGHT; if (this->m_Controls->m_StatisticsTable->horizontalHeader()->isVisible()) height += this->m_Controls->m_StatisticsTable->horizontalHeader()->height(); if (this->m_Controls->m_StatisticsTable->horizontalScrollBar()->isVisible()) height += this->m_Controls->m_StatisticsTable->horizontalScrollBar()->height(); this->m_Controls->m_StatisticsTable->setMinimumHeight(height); } void QmitkImageStatisticsView::InvalidateStatisticsTableView() { this->m_Controls->m_StatisticsTable->horizontalHeader()->setVisible(false); this->m_Controls->m_StatisticsTable->setColumnCount(1); for ( int i = 0; i < this->m_Controls->m_StatisticsTable->rowCount(); ++i ) { { this->m_Controls->m_StatisticsTable->setItem( i, 0, new QTableWidgetItem( "NA" ) ); } } this->m_Controls->m_StatisticsTable->setMinimumHeight(STAT_TABLE_BASE_HEIGHT); } void QmitkImageStatisticsView::Activated() { } void QmitkImageStatisticsView::Deactivated() { } void QmitkImageStatisticsView::Visible() { m_Visible = true; mitk::IRenderWindowPart* renderWindow = GetRenderWindowPart(); if (renderWindow) { itk::ReceptorMemberCommand::Pointer cmdTimeEvent = itk::ReceptorMemberCommand::New(); cmdTimeEvent->SetCallbackFunction(this, &QmitkImageStatisticsView::OnTimeChanged); // It is sufficient to add the observer to the axial render window since the GeometryTimeEvent // is always triggered by all views. m_TimeObserverTag = renderWindow->GetQmitkRenderWindow("axial")-> GetSliceNavigationController()-> AddObserver(mitk::SliceNavigationController::GeometryTimeEvent(nullptr, 0), cmdTimeEvent); } if (m_DataNodeSelectionChanged) { if (this->IsCurrentSelectionValid()) { this->SelectionChanged(this->GetCurrentSelection()); } else { this->SelectionChanged(this->GetDataManagerSelection()); } m_DataNodeSelectionChanged = false; } } void QmitkImageStatisticsView::Hidden() { m_Visible = false; // The slice navigation controller observer is removed here instead of in the destructor. // If it was called in the destructor, the application would freeze because the view's // destructor gets called after the render windows have been destructed. if ( m_TimeObserverTag != 0 ) { mitk::IRenderWindowPart* renderWindow = GetRenderWindowPart(); if (renderWindow) { renderWindow->GetQmitkRenderWindow("axial")->GetSliceNavigationController()-> RemoveObserver( m_TimeObserverTag ); } m_TimeObserverTag = 0; } } void QmitkImageStatisticsView::SetFocus() { } void QmitkImageStatisticsView::AdaptBinSizeCheckboxStepsize(mitk::Image::ConstPointer image) { auto componentType = image->GetPixelType().GetComponentType(); if (componentType == itk::ImageIOBase::DOUBLE || componentType == itk::ImageIOBase::FLOAT) { m_Controls->m_HistogramBinSizeSpinbox->setDecimals(2); m_Controls->m_HistogramBinSizeSpinbox->setSingleStep(.01); } else { m_Controls->m_HistogramBinSizeSpinbox->setDecimals(0); m_Controls->m_HistogramBinSizeSpinbox->setSingleStep(1); } } void QmitkImageStatisticsView::AdaptBinSizeCheckBoxMinMax(mitk::ImageStatisticsCalculator::StatisticsContainer::ConstPointer statistics, int componentType) { auto minValue = statistics->GetMin(); auto maxValue = statistics->GetMax(); //10 bins are minimum as defined in ImageStatisticsCalculator::GetStatistics const unsigned int minHistogramBins = 10; //10000 bins are just a maximum arbitrary number to keep computation time reasonable const unsigned int maxHistogramBins = 10000; double minHistogramBinSize = static_cast((maxValue - minValue) / maxHistogramBins); double maxHistogramBinSize = static_cast((maxValue - minValue) / minHistogramBins); if (componentType == itk::ImageIOBase::DOUBLE || componentType == itk::ImageIOBase::FLOAT) { //smallest value for double/float images const double minHistogramBinSizeValid = 0.01; m_Controls->m_HistogramBinSizeSpinbox->setMinimum(std::max(minHistogramBinSize, minHistogramBinSizeValid)); m_Controls->m_HistogramBinSizeSpinbox->setMaximum(maxHistogramBinSize); } else { //smallest valid value for int/short images const double minHistogramBinSizeValid = 1; m_Controls->m_HistogramBinSizeSpinbox->setMinimum(std::max(static_cast(minHistogramBinSize), static_cast(minHistogramBinSizeValid))); m_Controls->m_HistogramBinSizeSpinbox->setMaximum(static_cast(maxHistogramBinSize)); } } std::map QmitkImageStatisticsView::ConvertHistogramToMap(itk::Statistics::Histogram::ConstPointer histogram) const { std::map histogramMap; auto endIt = histogram->End(); auto it = histogram->Begin(); // generating Lists of measurement and frequencies for (; it != endIt; ++it) { double frequency = it.GetFrequency(); double measurement = it.GetMeasurementVector()[0]; histogramMap.emplace(measurement, frequency); } return histogramMap; } std::vector QmitkImageStatisticsView::ConvertIntensityProfileToVector(mitk::IntensityProfile::ConstPointer intensityProfile) const { std::vector intensityProfileList; auto end = intensityProfile->End(); for (auto it = intensityProfile->Begin(); it != end; ++it) { intensityProfileList.push_back(it.GetMeasurementVector()[0]); } return intensityProfileList; } QString QmitkImageStatisticsView::GetFormattedString(double value, unsigned int decimals) const { typedef mitk::ImageStatisticsCalculator::StatisticsContainer::RealType RealType; RealType maxVal = std::numeric_limits::max(); if (value == maxVal) { return QString("NA"); } else { return QString("%1").arg(value, 0, 'f', decimals); } } QString QmitkImageStatisticsView::GetFormattedIndex(const vnl_vector& vector) const { if (vector.empty()) { return QString(); } QString formattedIndex("("); for (const auto& entry : vector) { formattedIndex += QString::number(entry); formattedIndex += ","; } formattedIndex.chop(1); formattedIndex += ")"; return formattedIndex; } diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/CMakeLists.txt b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/CMakeLists.txt index ce750d05d7..0b44d554e6 100644 --- a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/CMakeLists.txt +++ b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/CMakeLists.txt @@ -1,7 +1,11 @@ project(org_mitk_gui_qt_photoacoustics_imageprocessing) mitk_create_plugin( EXPORT_DIRECTIVE IMAGEPROCESSING_EXPORT EXPORTED_INCLUDE_SUFFIXES src MODULE_DEPENDS MitkQtWidgetsExt MitkPhotoacousticsAlgorithms ) + +IF(MITK_USE_OpenCL) + add_definitions(-DPHOTOACOUSTICS_USE_GPU) +ENDIF(MITK_USE_OpenCL) \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/documentation/UserManual/Manual.dox b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/documentation/UserManual/Manual.dox index d96263f413..0aea28cd07 100644 --- a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/documentation/UserManual/Manual.dox +++ b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/documentation/UserManual/Manual.dox @@ -1,17 +1,62 @@ /** -\page org_mitk_gui_qt_photoacoustics_imageprocessing The Imageprocessing +\page org_mitk_gui_qt_photoacoustics_imageprocessing The Photoacoustics Imageprocessing Plugin -\imageMacro{icon.png,"Icon of Imageprocessing",2.00} +\imageMacro{pai.png,"Icon of Imageprocessing",2.00} \tableofcontents \section org_mitk_gui_qt_photoacoustics_imageprocessingOverview Overview -Describe the features of your awesome plugin here +This plugin offers an interface to perform image processing on photoacoustic, as well as ultrasound images, i.e. to use beamforming and post-processing filters. +For convenience, image processing can be done automatically for a whole batch of files containing PA or US data. + +\section org_mitk_gui_qt_photoacoustics_imageprocessingPrerequisites Prerequisites +To use the much more performant openCL filters which run on the graphics card, MITK has to be able to use openCL, for which it is necessary to install the openCL implementation provided by your graphics card vendor. + +\section org_mitk_gui_qt_photoacoustics_imageprocessingFiltering Using the filters +To perform image processing, simply load an image into MITK and select it in the Data manager. Only the selected image will be processed by the filters. +\imageMacro{QmikPhotoacousticsImageProcessing_DataManager.png,"Select the image to be processed",7.62} +Before performing reconstruction or using other filters those can be configured using the plugin's settings panel. +\imageMacro{QmikPhotoacousticsImageProcessing_Settings.png,"The plugin's GUI",7.62} + +\subsection org_mitk_gui_qt_photoacoustics_imageprocessingBeamforming The Beamforming Settings +For beamforming, three beamforming algorithms are available: +
    +
  • DAS (Delay And Sum) +
  • DMAS (Delay Multiply And Sum) +
  • sDMAS (signed Delay Multiply And Sum) +
+Each of those can be coupled with either spherical delay calculation or a quadratic approximation for the delays. To supress noise, one of the following apodizations can be chosen to be used when beamforming: +
    +
  • Box (No apodization) +
  • Hamming +
  • Von Hann +
+Other Standard beamforming parameters are available, which have to be chosen depending on the source image to attain a correctly reconstructed image. +The Plugin is able to calculate the used scan depth as well as the transducer pitch from the selected image if the time-axis spacing is in microseconds, and the horizontal spacing in mm. If such a spacing is given, +check the box "Auto Get Depth" to make the plugin read those values by itself. +If the US source or the laser used for imaging is not located at the top of the image, an option is given to cut off pixels at the top of the image until the source. This value should be calibrated by the user +to match the used hardware. +If one wishes to beamform only certain slices of a given image, those can be selected by checking "select slices" and setting the "min" and "max" values accordingly, which are to be understood as closed interval boundaries. + +\subsection org_mitk_gui_qt_photoacoustics_imageprocessingBandpass The Bandpass Settings +The bandpass uses an itk implementation of an 1D Fast Fourier Transform (FFT) to transform the image vertically, then filters the image using a Tukey window in the frequency domain and performs an inverse 1D FFT to get the filtered image. +The "smoothness" of the tukey window can be chosen by using the "Tukey window alpha" parameter. The Tukey window interpolates between a Box window (alpha = 0) and a Von Hann window (alpha = 1). +The filtered frequencies can be set by defining the High and Low pass frequencies. + +\subsection org_mitk_gui_qt_photoacoustics_imageprocessingCrop The Crop Filter Settings +The crop filter cuts off parts of the image at the top and the bottom. The amount of pixels cut off can be configured using the "Cut Top" and "Cut Bottom" parameters. + +\subsection org_mitk_gui_qt_photoacoustics_imageprocessingBMode The BMode Filter Settings +The B-mode filters available are:
    -
  • Increases productivity -
  • Creates beautiful images -
  • Generates PhD thesis -
  • Brings world peace +
  • An absolute filter +
  • An envelope detection filter
+If desired, the filter can also resample the image to a given spacing; to do this, check the "Do Resampling" box and set the desired spacing in mm. +Afterwards a logarithmic filter can be applied, if "Add Logfilter" is checked. +\subsection org_mitk_gui_qt_photoacoustics_imageprocessingBatch Batch Processing +When processing large amounts of data, an option is available to automatically process multiple images by applying all filters in order to those images and saving the resulting images. +In the first row of the Batch Processing Panel one can select which filters should be applied to the image; in the second row one can select whether the resulting image from the filter should be saved. +After pressing the "Start Batch Processing" button, one can choose first the images to be processed, and then the folder where they will be saved. */ diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/documentation/UserManual/QmikPhotoacousticsImageProcessing_DataManager.png b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/documentation/UserManual/QmikPhotoacousticsImageProcessing_DataManager.png new file mode 100644 index 0000000000..29b7b0e002 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/documentation/UserManual/QmikPhotoacousticsImageProcessing_DataManager.png differ diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/documentation/UserManual/QmikPhotoacousticsImageProcessing_Settings.png b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/documentation/UserManual/QmikPhotoacousticsImageProcessing_Settings.png new file mode 100644 index 0000000000..f8210298cf Binary files /dev/null and b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/documentation/UserManual/QmikPhotoacousticsImageProcessing_Settings.png differ diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/documentation/UserManual/icon.xpm b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/documentation/UserManual/icon.xpm deleted file mode 100644 index 9057c20bc6..0000000000 --- a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/documentation/UserManual/icon.xpm +++ /dev/null @@ -1,21 +0,0 @@ -/* XPM */ -static const char * icon_xpm[] = { -"16 16 2 1", -" c #FF0000", -". c #000000", -" ", -" ", -" ", -" ", -" ", -" ", -" ", -" ", -" ", -" ", -" ", -" ", -" ", -" ", -" ", -" "}; diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/documentation/UserManual/pai.png b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/documentation/UserManual/pai.png new file mode 100644 index 0000000000..1b8dc34c11 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/documentation/UserManual/pai.png differ diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/resources/pai.png b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/resources/pai.png new file mode 100644 index 0000000000..1b8dc34c11 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/resources/pai.png differ diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessing.cpp b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessing.cpp index 8c59dee114..84c5f9668f 100644 --- a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessing.cpp +++ b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessing.cpp @@ -1,1080 +1,1161 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // Blueberry #include #include // Qmitk #include "PAImageProcessing.h" // Qt #include #include #include #include //mitk image #include #include "mitkPhotoacousticImage.h" #include "mitkPhotoacousticBeamformingFilter.h" //other #include #include #include const std::string PAImageProcessing::VIEW_ID = "org.mitk.views.paimageprocessing"; -PAImageProcessing::PAImageProcessing() : m_ResampleSpacing(0), m_UseLogfilter(false) +PAImageProcessing::PAImageProcessing() : m_ResampleSpacing(0), m_UseLogfilter(false), m_FilterBank(mitk::PhotoacousticImage::New()) { qRegisterMetaType(); qRegisterMetaType(); } void PAImageProcessing::SetFocus() { m_Controls.buttonApplyBModeFilter->setFocus(); } void PAImageProcessing::CreateQtPartControl(QWidget *parent) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi(parent); connect(m_Controls.buttonApplyBModeFilter, SIGNAL(clicked()), this, SLOT(StartBmodeThread())); connect(m_Controls.DoResampling, SIGNAL(clicked()), this, SLOT(UseResampling())); connect(m_Controls.Logfilter, SIGNAL(clicked()), this, SLOT(UseLogfilter())); connect(m_Controls.ResamplingValue, SIGNAL(valueChanged(double)), this, SLOT(SetResampling())); connect(m_Controls.buttonApplyBeamforming, SIGNAL(clicked()), this, SLOT(StartBeamformingThread())); connect(m_Controls.buttonApplyCropFilter, SIGNAL(clicked()), this, SLOT(StartCropThread())); connect(m_Controls.buttonApplyBandpass, SIGNAL(clicked()), this, SLOT(StartBandpassThread())); connect(m_Controls.UseImageSpacing, SIGNAL(clicked()), this, SLOT(UseImageSpacing())); connect(m_Controls.ScanDepth, SIGNAL(valueChanged(double)), this, SLOT(UpdateImageInfo())); connect(m_Controls.SpeedOfSound, SIGNAL(valueChanged(double)), this, SLOT(UpdateImageInfo())); + connect(m_Controls.SpeedOfSound, SIGNAL(valueChanged(double)), this, SLOT(ChangedSOSBeamforming())); + connect(m_Controls.BPSpeedOfSound, SIGNAL(valueChanged(double)), this, SLOT(ChangedSOSBandpass())); connect(m_Controls.Samples, SIGNAL(valueChanged(int)), this, SLOT(UpdateImageInfo())); connect(m_Controls.UseImageSpacing, SIGNAL(clicked()), this, SLOT(UpdateImageInfo())); - connect(m_Controls.boundLow, SIGNAL(valueChanged(int)), this, SLOT(UpdateBounds())); - connect(m_Controls.boundHigh, SIGNAL(valueChanged(int)), this, SLOT(UpdateBounds())); - connect(m_Controls.Partial, SIGNAL(clicked()), this, SLOT(UpdateBounds())); + connect(m_Controls.boundLow, SIGNAL(valueChanged(int)), this, SLOT(LowerSliceBoundChanged())); + connect(m_Controls.boundHigh, SIGNAL(valueChanged(int)), this, SLOT(UpperSliceBoundChanged())); + connect(m_Controls.Partial, SIGNAL(clicked()), this, SLOT(SliceBoundsEnabled())); connect(m_Controls.BatchProcessing, SIGNAL(clicked()), this, SLOT(BatchProcessing())); connect(m_Controls.StepBeamforming, SIGNAL(clicked()), this, SLOT(UpdateSaveBoxes())); connect(m_Controls.StepCropping, SIGNAL(clicked()), this, SLOT(UpdateSaveBoxes())); connect(m_Controls.StepBandpass, SIGNAL(clicked()), this, SLOT(UpdateSaveBoxes())); connect(m_Controls.StepBMode, SIGNAL(clicked()), this, SLOT(UpdateSaveBoxes())); UpdateSaveBoxes(); m_Controls.DoResampling->setChecked(false); m_Controls.ResamplingValue->setEnabled(false); m_Controls.progressBar->setMinimum(0); m_Controls.progressBar->setMaximum(100); m_Controls.progressBar->setVisible(false); m_Controls.UseImageSpacing->setToolTip("Image spacing of y-Axis must be in us, x-Axis in mm."); m_Controls.UseImageSpacing->setToolTipDuration(5000); m_Controls.ProgressInfo->setVisible(false); m_Controls.UseBP->hide(); - + m_Controls.UseGPUBmode->hide(); + + #ifndef PHOTOACOUSTICS_USE_GPU + m_Controls.UseGPUBf->setEnabled(false); + m_Controls.UseGPUBf->setChecked(false); + m_Controls.UseGPUBmode->setEnabled(false); + m_Controls.UseGPUBmode->setChecked(false); + #endif + UseImageSpacing(); } +void PAImageProcessing::ChangedSOSBandpass() +{ + m_Controls.SpeedOfSound->setValue(m_Controls.BPSpeedOfSound->value()); +} + +void PAImageProcessing::ChangedSOSBeamforming() +{ + m_Controls.BPSpeedOfSound->setValue(m_Controls.SpeedOfSound->value()); +} + std::vector splitpath( const std::string& str , const std::set delimiters) { std::vector result; char const* pch = str.c_str(); char const* start = pch; for (; *pch; ++pch) { if (delimiters.find(*pch) != delimiters.end()) { if (start != pch) { std::string str(start, pch); result.push_back(str); } else { result.push_back(""); } start = pch + 1; } } result.push_back(start); return result; } void PAImageProcessing::UpdateSaveBoxes() { if (m_Controls.StepBeamforming->isChecked()) m_Controls.SaveBeamforming->setEnabled(true); else m_Controls.SaveBeamforming->setEnabled(false); if (m_Controls.StepCropping->isChecked()) m_Controls.SaveCropping->setEnabled(true); else m_Controls.SaveCropping->setEnabled(false); if (m_Controls.StepBandpass->isChecked()) m_Controls.SaveBandpass->setEnabled(true); else m_Controls.SaveBandpass->setEnabled(false); if (m_Controls.StepBMode->isChecked()) m_Controls.SaveBMode->setEnabled(true); else m_Controls.SaveBMode->setEnabled(false); } void PAImageProcessing::BatchProcessing() { QFileDialog LoadDialog(nullptr, "Select Files to be processed"); LoadDialog.setFileMode(QFileDialog::FileMode::ExistingFiles); LoadDialog.setNameFilter(tr("Images (*.nrrd)")); LoadDialog.setViewMode(QFileDialog::Detail); QStringList fileNames; if (LoadDialog.exec()) fileNames = LoadDialog.selectedFiles(); QString saveDir = QFileDialog::getExistingDirectory(nullptr, tr("Select Directory To Save To"), "", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); DisableControls(); std::set delims{'/'}; - mitk::PhotoacousticImage::Pointer filterbank = mitk::PhotoacousticImage::New(); - bool doSteps[] = { m_Controls.StepBeamforming->isChecked(), m_Controls.StepCropping->isChecked() , m_Controls.StepBandpass->isChecked(), m_Controls.StepBMode->isChecked() }; bool saveSteps[] = { m_Controls.SaveBeamforming->isChecked(), m_Controls.SaveCropping->isChecked() , m_Controls.SaveBandpass->isChecked(), m_Controls.SaveBMode->isChecked() }; for (int fileNumber = 0; fileNumber < fileNames.size(); ++fileNumber) { m_Controls.progressBar->setValue(0); m_Controls.progressBar->setVisible(true); m_Controls.ProgressInfo->setVisible(true); m_Controls.ProgressInfo->setText("loading file"); QString filename = fileNames.at(fileNumber); auto split = splitpath(filename.toStdString(), delims); std::string imageName = split.at(split.size()-1); // remove ".nrrd" imageName = imageName.substr(0, imageName.size()-5); mitk::Image::Pointer image = mitk::IOUtil::LoadImage(filename.toStdString().c_str()); UpdateBFSettings(image); // Beamforming if (doSteps[0]) { std::function progressHandle = [this](int progress, std::string progressInfo) { this->UpdateProgress(progress, progressInfo); }; m_Controls.progressBar->setValue(100); + std::string errorMessage = ""; - image = filterbank->ApplyBeamforming(image, BFconfig, m_Controls.Cutoff->value(), progressHandle); + image = m_FilterBank->ApplyBeamforming(image, BFconfig, errorMessage, progressHandle); if (saveSteps[0]) { std::string saveFileName = saveDir.toStdString() + "/" + imageName + " beamformed" + ".nrrd"; mitk::IOUtil::Save(image, saveFileName); } } // Cropping if (doSteps[1]) { m_Controls.ProgressInfo->setText("cropping image"); - image = filterbank->ApplyCropping(image, m_Controls.CutoffAbove->value(), m_Controls.CutoffBelow->value(), 0, 0, 0, image->GetDimension(2) - 1); + image = m_FilterBank->ApplyCropping(image, m_Controls.CutoffAbove->value(), m_Controls.CutoffBelow->value(), 0, 0, 0, image->GetDimension(2) - 1); if (saveSteps[1]) { std::string saveFileName = saveDir.toStdString() + "/" + imageName + " cropped" + ".nrrd"; mitk::IOUtil::Save(image, saveFileName); } } // Bandpass if (doSteps[2]) { m_Controls.ProgressInfo->setText("applying bandpass"); float recordTime = image->GetDimension(1)*image->GetGeometry()->GetSpacing()[1] / 1000 / m_Controls.BPSpeedOfSound->value(); // add a safeguard so the program does not chrash when applying a Bandpass that reaches out of the bounds of the image float maxFrequency = 1 / (recordTime / image->GetDimension(1)) * image->GetDimension(1) / 2 / 2 / 1000; float BPHighPass = 1000000 * m_Controls.BPhigh->value(); // [Hz] float BPLowPass = maxFrequency - 1000000 * m_Controls.BPlow->value(); // [Hz] if (BPLowPass > maxFrequency && m_Controls.UseBP->isChecked()) { QMessageBox Msgbox; Msgbox.setText("LowPass too low, disabled it."); Msgbox.exec(); BPLowPass = 0; } if (BPLowPass < 0 && m_Controls.UseBP->isChecked()) { QMessageBox Msgbox; Msgbox.setText("LowPass too high, disabled it."); Msgbox.exec(); BPLowPass = 0; } if (BPHighPass > maxFrequency && m_Controls.UseBP->isChecked()) { QMessageBox Msgbox; Msgbox.setText("HighPass too high, disabled it."); Msgbox.exec(); BPHighPass = 0; } if (BPHighPass > maxFrequency - BFconfig.BPLowPass) { QMessageBox Msgbox; Msgbox.setText("HighPass higher than LowPass, disabled both."); Msgbox.exec(); BPHighPass = 0; BPLowPass = 0; } - image = filterbank->BandpassFilter(image, recordTime, BPHighPass, BPLowPass, m_Controls.BPFalloff->value()); + image = m_FilterBank->BandpassFilter(image, recordTime, BPHighPass, BPLowPass, m_Controls.BPFalloff->value()); if (saveSteps[2]) { std::string saveFileName = saveDir.toStdString() + "/" + imageName + " bandpassed" + ".nrrd"; mitk::IOUtil::Save(image, saveFileName); } } // Bmode if (doSteps[3]) { m_Controls.ProgressInfo->setText("applying bmode filter"); - - if (m_Controls.BModeMethod->currentText() == "Simple Abs Filter") - image = filterbank->ApplyBmodeFilter(image, mitk::PhotoacousticImage::BModeMethod::Abs, m_UseLogfilter, m_ResampleSpacing); - else if (m_Controls.BModeMethod->currentText() == "Shape Detection") - image = filterbank->ApplyBmodeFilter(image, mitk::PhotoacousticImage::BModeMethod::ShapeDetection, m_UseLogfilter, m_ResampleSpacing); + bool useGPU = m_Controls.UseGPUBmode->isChecked(); + + if (m_Controls.BModeMethod->currentText() == "Absolute Filter") + image = m_FilterBank->ApplyBmodeFilter(image, mitk::PhotoacousticImage::BModeMethod::Abs, useGPU, m_UseLogfilter, m_ResampleSpacing); + else if (m_Controls.BModeMethod->currentText() == "Envelope Detection") + image = m_FilterBank->ApplyBmodeFilter(image, mitk::PhotoacousticImage::BModeMethod::EnvelopeDetection, useGPU, m_UseLogfilter, m_ResampleSpacing); + if (saveSteps[3]) { std::string saveFileName = saveDir.toStdString() + "/" + imageName + " bmode" + ".nrrd"; mitk::IOUtil::Save(image, saveFileName); } } m_Controls.progressBar->setVisible(false); } EnableControls(); } void PAImageProcessing::StartBeamformingThread() { QList nodes = this->GetDataManagerSelection(); if (nodes.empty()) return; mitk::DataStorage::Pointer storage = this->GetDataStorage(); mitk::DataNode::Pointer node = nodes.front(); if (!node) { // Nothing selected. Inform the user and return QMessageBox::information(NULL, "Template", "Please load and select an image before starting image processing."); return; } mitk::BaseData* data = node->GetData(); if (data) { // test if this data item is an image or not (could also be a surface or something totally different) mitk::Image* image = dynamic_cast(data); if (image) { UpdateBFSettings(image); std::stringstream message; std::string name; message << "Performing beamforming for image "; if (node->GetName(name)) { // a property called "name" was found for this DataNode message << "'" << name << "'"; m_OldNodeName = name; } else m_OldNodeName = " "; message << "."; MITK_INFO << message.str(); m_Controls.progressBar->setValue(0); m_Controls.progressBar->setVisible(true); m_Controls.ProgressInfo->setVisible(true); m_Controls.ProgressInfo->setText("started"); m_Controls.buttonApplyBeamforming->setText("working..."); DisableControls(); BeamformingThread *thread = new BeamformingThread(); connect(thread, &BeamformingThread::result, this, &PAImageProcessing::HandleBeamformingResults); connect(thread, &BeamformingThread::updateProgress, this, &PAImageProcessing::UpdateProgress); + connect(thread, &BeamformingThread::message, this, &PAImageProcessing::PAMessageBox); connect(thread, &BeamformingThread::finished, thread, &QObject::deleteLater); thread->setConfig(BFconfig); - thread->setCutoff(m_Controls.Cutoff->value()); thread->setInputImage(image); + thread->setFilterBank(m_FilterBank); MITK_INFO << "Started new thread for Beamforming"; thread->start(); } } } void PAImageProcessing::HandleBeamformingResults(mitk::Image::Pointer image) { auto newNode = mitk::DataNode::New(); newNode->SetData(image); // name the new Data node std::stringstream newNodeName; newNodeName << m_OldNodeName << " "; - if (BFconfig.Algorithm == mitk::BeamformingFilter::beamformingSettings::BeamformingAlgorithm::DAS) + if (BFconfig.Algorithm == mitk::BeamformingSettings::BeamformingAlgorithm::DAS) newNodeName << "DAS bf, "; - else if (BFconfig.Algorithm == mitk::BeamformingFilter::beamformingSettings::BeamformingAlgorithm::DMAS) + else if (BFconfig.Algorithm == mitk::BeamformingSettings::BeamformingAlgorithm::DMAS) newNodeName << "DMAS bf, "; - if (BFconfig.DelayCalculationMethod == mitk::BeamformingFilter::beamformingSettings::DelayCalc::QuadApprox) + if (BFconfig.DelayCalculationMethod == mitk::BeamformingSettings::DelayCalc::QuadApprox) newNodeName << "q. delay"; - if (BFconfig.DelayCalculationMethod == mitk::BeamformingFilter::beamformingSettings::DelayCalc::Spherical) + if (BFconfig.DelayCalculationMethod == mitk::BeamformingSettings::DelayCalc::Spherical) newNodeName << "s. delay"; newNode->SetName(newNodeName.str()); // update level window for the current dynamic range mitk::LevelWindow levelWindow; newNode->GetLevelWindow(levelWindow); - auto data = newNode->GetData(); - levelWindow.SetAuto(dynamic_cast(data), true, true); + levelWindow.SetAuto(image, true, true); newNode->SetLevelWindow(levelWindow); // add new node to data storage this->GetDataStorage()->Add(newNode); // disable progress bar m_Controls.progressBar->setVisible(false); m_Controls.ProgressInfo->setVisible(false); m_Controls.buttonApplyBeamforming->setText("Apply Beamforming"); EnableControls(); // update rendering - mitk::RenderingManager::GetInstance()->InitializeViews( - dynamic_cast(data)->GetGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); + mitk::RenderingManager::GetInstance()->InitializeViews(image->GetGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void PAImageProcessing::StartBmodeThread() { QList nodes = this->GetDataManagerSelection(); if (nodes.empty()) return; mitk::DataStorage::Pointer storage = this->GetDataStorage(); mitk::DataNode::Pointer node = nodes.front(); if (!node) { // Nothing selected. Inform the user and return QMessageBox::information(NULL, "Template", "Please load and select an image before starting image processing."); return; } mitk::BaseData* data = node->GetData(); if (data) { // test if this data item is an image or not (could also be a surface or something totally different) mitk::Image* image = dynamic_cast(data); if (image) { UpdateBFSettings(image); std::stringstream message; std::string name; message << "Performing image processing for image "; if (node->GetName(name)) { // a property called "name" was found for this DataNode message << "'" << name << "'"; m_OldNodeName = name; } else m_OldNodeName = " "; message << "."; MITK_INFO << message.str(); m_Controls.buttonApplyBModeFilter->setText("working..."); DisableControls(); BmodeThread *thread = new BmodeThread(); connect(thread, &BmodeThread::result, this, &PAImageProcessing::HandleBmodeResults); connect(thread, &BmodeThread::finished, thread, &QObject::deleteLater); - if(m_Controls.BModeMethod->currentText() == "Simple Abs Filter") - thread->setConfig(m_UseLogfilter, m_ResampleSpacing, mitk::PhotoacousticImage::BModeMethod::Abs); - else if(m_Controls.BModeMethod->currentText() == "Shape Detection") - thread->setConfig(m_UseLogfilter, m_ResampleSpacing, mitk::PhotoacousticImage::BModeMethod::ShapeDetection); + bool useGPU = m_Controls.UseGPUBmode->isChecked(); + if(m_Controls.BModeMethod->currentText() == "Absolute Filter") + thread->setConfig(m_UseLogfilter, m_ResampleSpacing, mitk::PhotoacousticImage::BModeMethod::Abs, useGPU); + else if(m_Controls.BModeMethod->currentText() == "Envelope Detection") + thread->setConfig(m_UseLogfilter, m_ResampleSpacing, mitk::PhotoacousticImage::BModeMethod::EnvelopeDetection, useGPU); thread->setInputImage(image); + thread->setFilterBank(m_FilterBank); MITK_INFO << "Started new thread for Image Processing"; thread->start(); } } } void PAImageProcessing::HandleBmodeResults(mitk::Image::Pointer image) { auto newNode = mitk::DataNode::New(); newNode->SetData(image); // name the new Data node std::stringstream newNodeName; newNodeName << m_OldNodeName << " "; newNodeName << "B-Mode"; newNode->SetName(newNodeName.str()); // update level window for the current dynamic range mitk::LevelWindow levelWindow; newNode->GetLevelWindow(levelWindow); auto data = newNode->GetData(); levelWindow.SetAuto(dynamic_cast(data), true, true); newNode->SetLevelWindow(levelWindow); // add new node to data storage this->GetDataStorage()->Add(newNode); // disable progress bar m_Controls.progressBar->setVisible(false); m_Controls.buttonApplyBModeFilter->setText("Apply B-mode Filter"); EnableControls(); // update rendering mitk::RenderingManager::GetInstance()->InitializeViews( dynamic_cast(data)->GetGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void PAImageProcessing::StartCropThread() { QList nodes = this->GetDataManagerSelection(); if (nodes.empty()) return; mitk::DataStorage::Pointer storage = this->GetDataStorage(); mitk::DataNode::Pointer node = nodes.front(); if (!node) { // Nothing selected. Inform the user and return QMessageBox::information(NULL, "Template", "Please load and select an image before starting image cropping."); return; } mitk::BaseData* data = node->GetData(); if (data) { // test if this data item is an image or not (could also be a surface or something totally different) mitk::Image* image = dynamic_cast(data); if (image) { UpdateBFSettings(image); std::stringstream message; std::string name; message << "Performing image cropping for image "; if (node->GetName(name)) { // a property called "name" was found for this DataNode message << "'" << name << "'"; m_OldNodeName = name; } else m_OldNodeName = " "; message << "."; MITK_INFO << message.str(); m_Controls.buttonApplyCropFilter->setText("working..."); DisableControls(); CropThread *thread = new CropThread(); connect(thread, &CropThread::result, this, &PAImageProcessing::HandleCropResults); connect(thread, &CropThread::finished, thread, &QObject::deleteLater); - thread->setConfig(m_Controls.CutoffAbove->value(), m_Controls.CutoffBelow->value()); + thread->setConfig(m_Controls.CutoffAbove->value(), m_Controls.CutoffBelow->value(), 0, image->GetDimension(2) - 1); thread->setInputImage(image); + thread->setFilterBank(m_FilterBank); MITK_INFO << "Started new thread for Image Cropping"; thread->start(); } } } void PAImageProcessing::HandleCropResults(mitk::Image::Pointer image) { auto newNode = mitk::DataNode::New(); newNode->SetData(image); // name the new Data node std::stringstream newNodeName; newNodeName << m_OldNodeName << " "; newNodeName << "Cropped"; newNode->SetName(newNodeName.str()); // update level window for the current dynamic range mitk::LevelWindow levelWindow; newNode->GetLevelWindow(levelWindow); auto data = newNode->GetData(); levelWindow.SetAuto(dynamic_cast(data), true, true); newNode->SetLevelWindow(levelWindow); // add new node to data storage this->GetDataStorage()->Add(newNode); m_Controls.buttonApplyCropFilter->setText("Apply Crop Filter"); EnableControls(); // update rendering mitk::RenderingManager::GetInstance()->InitializeViews( dynamic_cast(data)->GetGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void PAImageProcessing::StartBandpassThread() { QList nodes = this->GetDataManagerSelection(); if (nodes.empty()) return; mitk::DataStorage::Pointer storage = this->GetDataStorage(); mitk::DataNode::Pointer node = nodes.front(); if (!node) { // Nothing selected. Inform the user and return QMessageBox::information(NULL, "Template", "Please load and select an image before starting image cropping."); return; } mitk::BaseData* data = node->GetData(); if (data) { // test if this data item is an image or not (could also be a surface or something totally different) mitk::Image* image = dynamic_cast(data); if (image) { UpdateBFSettings(image); std::stringstream message; std::string name; message << "Performing Bandpass filter on image "; if (node->GetName(name)) { // a property called "name" was found for this DataNode message << "'" << name << "'"; m_OldNodeName = name; } else m_OldNodeName = " "; message << "."; MITK_INFO << message.str(); m_Controls.buttonApplyBandpass->setText("working..."); DisableControls(); BandpassThread *thread = new BandpassThread(); connect(thread, &BandpassThread::result, this, &PAImageProcessing::HandleBandpassResults); connect(thread, &BandpassThread::finished, thread, &QObject::deleteLater); float recordTime = image->GetDimension(1)*image->GetGeometry()->GetSpacing()[1] / 1000 / m_Controls.BPSpeedOfSound->value(); // add a safeguard so the program does not chrash when applying a Bandpass that reaches out of the bounds of the image float maxFrequency = 1 / (recordTime / image->GetDimension(1)) * image->GetDimension(1) / 2 / 2 / 1000; float BPHighPass = 1000000 * m_Controls.BPhigh->value(); // [Hz] float BPLowPass = maxFrequency - 1000000 * m_Controls.BPlow->value(); // [Hz] if (BPLowPass > maxFrequency && m_Controls.UseBP->isChecked()) { QMessageBox Msgbox; Msgbox.setText("LowPass too low, disabled it."); Msgbox.exec(); BPLowPass = 0; } if (BPLowPass < 0 && m_Controls.UseBP->isChecked()) { QMessageBox Msgbox; Msgbox.setText("LowPass too high, disabled it."); Msgbox.exec(); BPLowPass = 0; } if (BPHighPass > maxFrequency && m_Controls.UseBP->isChecked()) { QMessageBox Msgbox; Msgbox.setText("HighPass too high, disabled it."); Msgbox.exec(); BPHighPass = 0; } if (BPHighPass > maxFrequency - BFconfig.BPLowPass) { QMessageBox Msgbox; Msgbox.setText("HighPass higher than LowPass, disabled both."); Msgbox.exec(); BPHighPass = 0; BPLowPass = 0; } thread->setConfig(BPHighPass, BPLowPass, m_Controls.BPFalloff->value(), recordTime); thread->setInputImage(image); + thread->setFilterBank(m_FilterBank); MITK_INFO << "Started new thread for Bandpass filter"; thread->start(); } } } void PAImageProcessing::HandleBandpassResults(mitk::Image::Pointer image) { auto newNode = mitk::DataNode::New(); newNode->SetData(image); // name the new Data node std::stringstream newNodeName; newNodeName << m_OldNodeName << " "; newNodeName << "Bandpassed"; newNode->SetName(newNodeName.str()); // update level window for the current dynamic range mitk::LevelWindow levelWindow; newNode->GetLevelWindow(levelWindow); auto data = newNode->GetData(); levelWindow.SetAuto(dynamic_cast(data), true, true); newNode->SetLevelWindow(levelWindow); // add new node to data storage this->GetDataStorage()->Add(newNode); m_Controls.buttonApplyBandpass->setText("Apply Bandpass"); EnableControls(); // update rendering mitk::RenderingManager::GetInstance()->InitializeViews( dynamic_cast(data)->GetGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } -void PAImageProcessing::UpdateBounds() +void PAImageProcessing::SliceBoundsEnabled() { if (!m_Controls.Partial->isChecked()) { m_Controls.boundLow->setEnabled(false); m_Controls.boundHigh->setEnabled(false); - BFconfig.partial = false; return; } else { m_Controls.boundLow->setEnabled(true); m_Controls.boundHigh->setEnabled(true); - BFconfig.partial = true; } +} - if(m_Controls.boundLow->value()>m_Controls.boundHigh->value()) +void PAImageProcessing::UpperSliceBoundChanged() +{ + if(m_Controls.boundLow->value() > m_Controls.boundHigh->value()) { - MITK_INFO << "high bound < low bound -> setting both to beamform only first slice"; - m_Controls.boundLow->setValue(0); - m_Controls.boundHigh->setValue(0); - BFconfig.CropBounds[0] = 0; - BFconfig.CropBounds[1] = 0; + m_Controls.boundLow->setValue(m_Controls.boundHigh->value()); } - else +} + +void PAImageProcessing::LowerSliceBoundChanged() +{ + if (m_Controls.boundLow->value() > m_Controls.boundHigh->value()) { - BFconfig.CropBounds[0] = m_Controls.boundLow->value(); - BFconfig.CropBounds[1] = m_Controls.boundHigh->value(); + m_Controls.boundHigh->setValue(m_Controls.boundLow->value()); } } void PAImageProcessing::UpdateProgress(int progress, std::string progressInfo) { if (progress < 100) m_Controls.progressBar->setValue(progress); else m_Controls.progressBar->setValue(100); m_Controls.ProgressInfo->setText(progressInfo.c_str()); qApp->processEvents(); } +void PAImageProcessing::PAMessageBox(std::string message) +{ + if (0 != message.compare("noMessage")) + { + QMessageBox msgBox; + msgBox.setText(message.c_str()); + msgBox.exec(); + } +} + void PAImageProcessing::UpdateImageInfo() { QList nodes = this->GetDataManagerSelection(); if (nodes.empty()) return; mitk::DataNode::Pointer node = nodes.front(); if (!node) { // Nothing selected return; } mitk::BaseData* data = node->GetData(); if (data) { // test if this data item is an image or not (could also be a surface or something totally different) mitk::Image* image = dynamic_cast(data); if (image) { // beamforming configs if (m_Controls.UseImageSpacing->isChecked()) { m_Controls.ElementCount->setValue(image->GetDimension(0)); m_Controls.Pitch->setValue(image->GetGeometry()->GetSpacing()[0]); - m_Controls.boundLow->setMaximum(image->GetDimension(2) - 1); } - UpdateRecordTime(image); - // bandpass configs - float speedOfSound = m_Controls.BPSpeedOfSound->value(); // [m/s] - float recordTime = image->GetDimension(1)*image->GetGeometry()->GetSpacing()[1] / 1000 / speedOfSound; + m_Controls.boundLow->setMaximum(image->GetDimension(2) - 1); + m_Controls.boundHigh->setMaximum(image->GetDimension(2) - 1); + + UpdateBFSettings(image); + + m_Controls.CutoffBeforeBF->setValue(0.000001 / BFconfig.TimeSpacing); // 1us standard offset for our transducer std::stringstream frequency; - float maxFrequency = 1 / (recordTime / image->GetDimension(1)) * image->GetDimension(1) / 2 / 2 / 1000; + float maxFrequency = (1 / BFconfig.TimeSpacing) * image->GetDimension(1) / 2 / 2 / 1000; frequency << maxFrequency / 1000000; //[MHz] frequency << "MHz"; m_Controls.BPhigh->setMaximum(maxFrequency / 1000000); m_Controls.BPlow->setMaximum(maxFrequency / 1000000); frequency << " is the maximal allowed frequency for the selected image."; m_Controls.BPhigh->setToolTip(frequency.str().c_str()); m_Controls.BPlow->setToolTip(frequency.str().c_str()); m_Controls.BPhigh->setToolTipDuration(5000); m_Controls.BPlow->setToolTipDuration(5000); } } } void PAImageProcessing::OnSelectionChanged( berry::IWorkbenchPart::Pointer /*source*/, const QList& nodes ) { // iterate all selected objects, adjust warning visibility foreach( mitk::DataNode::Pointer node, nodes ) { if( node.IsNotNull() && dynamic_cast(node->GetData()) ) { m_Controls.labelWarning->setVisible( false ); m_Controls.buttonApplyBModeFilter->setEnabled( true ); m_Controls.labelWarning2->setVisible(false); m_Controls.buttonApplyCropFilter->setEnabled(true); m_Controls.labelWarning3->setVisible(false); m_Controls.buttonApplyBandpass->setEnabled(true); + m_Controls.labelWarning4->setVisible(false); + m_Controls.buttonApplyBeamforming->setEnabled(true); UpdateImageInfo(); return; } } m_Controls.labelWarning->setVisible( true ); m_Controls.buttonApplyBModeFilter->setEnabled( false ); m_Controls.labelWarning2->setVisible(true); m_Controls.buttonApplyCropFilter->setEnabled(false); m_Controls.labelWarning3->setVisible(true); m_Controls.buttonApplyBandpass->setEnabled(false); + m_Controls.labelWarning4->setVisible(true); + m_Controls.buttonApplyBeamforming->setEnabled(false); } void PAImageProcessing::UseResampling() { if (m_Controls.DoResampling->isChecked()) { m_Controls.ResamplingValue->setEnabled(true); m_ResampleSpacing = m_Controls.ResamplingValue->value(); } else { m_Controls.ResamplingValue->setEnabled(false); m_ResampleSpacing = 0; } } void PAImageProcessing::UseLogfilter() { m_UseLogfilter = m_Controls.Logfilter->isChecked(); } void PAImageProcessing::SetResampling() { m_ResampleSpacing = m_Controls.ResamplingValue->value(); } void PAImageProcessing::UpdateBFSettings(mitk::Image::Pointer image) { if ("DAS" == m_Controls.BFAlgorithm->currentText()) - BFconfig.Algorithm = mitk::BeamformingFilter::beamformingSettings::BeamformingAlgorithm::DAS; + BFconfig.Algorithm = mitk::BeamformingSettings::BeamformingAlgorithm::DAS; else if ("DMAS" == m_Controls.BFAlgorithm->currentText()) - BFconfig.Algorithm = mitk::BeamformingFilter::beamformingSettings::BeamformingAlgorithm::DMAS; + BFconfig.Algorithm = mitk::BeamformingSettings::BeamformingAlgorithm::DMAS; + else if ("sDMAS" == m_Controls.BFAlgorithm->currentText()) + BFconfig.Algorithm = mitk::BeamformingSettings::BeamformingAlgorithm::sDMAS; if ("Quad. Approx." == m_Controls.DelayCalculation->currentText()) { - BFconfig.DelayCalculationMethod = mitk::BeamformingFilter::beamformingSettings::DelayCalc::QuadApprox; + BFconfig.DelayCalculationMethod = mitk::BeamformingSettings::DelayCalc::QuadApprox; } else if ("Spherical Wave" == m_Controls.DelayCalculation->currentText()) { - BFconfig.DelayCalculationMethod = mitk::BeamformingFilter::beamformingSettings::DelayCalc::Spherical; + BFconfig.DelayCalculationMethod = mitk::BeamformingSettings::DelayCalc::Spherical; } if ("Von Hann" == m_Controls.Apodization->currentText()) { - BFconfig.Apod = mitk::BeamformingFilter::beamformingSettings::Apodization::Hann; + BFconfig.Apod = mitk::BeamformingSettings::Apodization::Hann; } else if ("Hamming" == m_Controls.Apodization->currentText()) { - BFconfig.Apod = mitk::BeamformingFilter::beamformingSettings::Apodization::Hamm; + BFconfig.Apod = mitk::BeamformingSettings::Apodization::Hamm; } else if ("Box" == m_Controls.Apodization->currentText()) { - BFconfig.Apod = mitk::BeamformingFilter::beamformingSettings::Apodization::Box; + BFconfig.Apod = mitk::BeamformingSettings::Apodization::Box; } BFconfig.Pitch = m_Controls.Pitch->value() / 1000; // [m] BFconfig.SpeedOfSound = m_Controls.SpeedOfSound->value(); // [m/s] BFconfig.SamplesPerLine = m_Controls.Samples->value(); BFconfig.ReconstructionLines = m_Controls.Lines->value(); BFconfig.TransducerElements = m_Controls.ElementCount->value(); + BFconfig.apodizationArraySize = m_Controls.Lines->value(); BFconfig.Angle = m_Controls.Angle->value(); // [deg] BFconfig.UseBP = m_Controls.UseBP->isChecked(); - BFconfig.UseGPU = m_Controls.UseGPU->isChecked(); + BFconfig.UseGPU = m_Controls.UseGPUBf->isChecked(); + BFconfig.upperCutoff = m_Controls.CutoffBeforeBF->value(); - UpdateRecordTime(image); - UpdateBounds(); -} - -void PAImageProcessing::UpdateRecordTime(mitk::Image::Pointer image) -{ if (m_Controls.UseImageSpacing->isChecked()) { BFconfig.RecordTime = image->GetDimension(1)*image->GetGeometry()->GetSpacing()[1] / 1000000; // [s] BFconfig.TimeSpacing = image->GetGeometry()->GetSpacing()[1] / 1000000; - MITK_INFO << "Calculated Scan Depth of " << BFconfig.RecordTime * BFconfig.SpeedOfSound * 100 << "cm"; + MITK_INFO << "Calculated Scan Depth of " << BFconfig.RecordTime * BFconfig.SpeedOfSound * 100 / 2 << "cm"; } else { BFconfig.RecordTime = 2 * m_Controls.ScanDepth->value() / 1000 / BFconfig.SpeedOfSound; // [s] BFconfig.TimeSpacing = BFconfig.RecordTime / image->GetDimension(1); } if ("US Image" == m_Controls.ImageType->currentText()) { - BFconfig.Photoacoustic = false; + BFconfig.isPhotoacousticImage = false; } else if ("PA Image" == m_Controls.ImageType->currentText()) { - BFconfig.Photoacoustic = true; + BFconfig.isPhotoacousticImage = true; } + + BFconfig.partial = m_Controls.Partial->isChecked(); + BFconfig.CropBounds[0] = m_Controls.boundLow->value(); + BFconfig.CropBounds[1] = m_Controls.boundHigh->value(); } void PAImageProcessing::EnableControls() { + m_Controls.BatchProcessing->setEnabled(true); + m_Controls.StepBeamforming->setEnabled(true); + m_Controls.StepBandpass->setEnabled(true); + m_Controls.StepCropping->setEnabled(true); + m_Controls.StepBMode->setEnabled(true); + + UpdateSaveBoxes(); + m_Controls.DoResampling->setEnabled(true); UseResampling(); m_Controls.Logfilter->setEnabled(true); + m_Controls.BModeMethod->setEnabled(true); m_Controls.buttonApplyBModeFilter->setEnabled(true); m_Controls.CutoffAbove->setEnabled(true); m_Controls.CutoffBelow->setEnabled(true); - m_Controls.Cutoff->setEnabled(true); + m_Controls.CutoffBeforeBF->setEnabled(true); m_Controls.buttonApplyCropFilter->setEnabled(true); - + m_Controls.BPSpeedOfSound->setEnabled(true); m_Controls.buttonApplyBandpass->setEnabled(true); + m_Controls.Partial->setEnabled(true); + m_Controls.boundHigh->setEnabled(true); + m_Controls.boundLow->setEnabled(true); m_Controls.BFAlgorithm->setEnabled(true); m_Controls.DelayCalculation->setEnabled(true); m_Controls.ImageType->setEnabled(true); m_Controls.Apodization->setEnabled(true); m_Controls.UseBP->setEnabled(true); - m_Controls.UseGPU->setEnabled(true); + + #ifdef PHOTOACOUSTICS_USE_GPU + m_Controls.UseGPUBf->setEnabled(true); + m_Controls.UseGPUBmode->setEnabled(true); + #endif + m_Controls.BPhigh->setEnabled(true); m_Controls.BPlow->setEnabled(true); m_Controls.BPFalloff->setEnabled(true); m_Controls.UseImageSpacing->setEnabled(true); UseImageSpacing(); m_Controls.Pitch->setEnabled(true); m_Controls.ElementCount->setEnabled(true); m_Controls.SpeedOfSound->setEnabled(true); m_Controls.Samples->setEnabled(true); m_Controls.Lines->setEnabled(true); m_Controls.Angle->setEnabled(true); m_Controls.buttonApplyBeamforming->setEnabled(true); } void PAImageProcessing::DisableControls() { + m_Controls.BatchProcessing->setEnabled(false); + m_Controls.StepBeamforming->setEnabled(false); + m_Controls.StepBandpass->setEnabled(false); + m_Controls.StepCropping->setEnabled(false); + m_Controls.StepBMode->setEnabled(false); + m_Controls.SaveBeamforming->setEnabled(false); + m_Controls.SaveBandpass->setEnabled(false); + m_Controls.SaveCropping->setEnabled(false); + m_Controls.SaveBMode->setEnabled(false); + m_Controls.DoResampling->setEnabled(false); m_Controls.ResamplingValue->setEnabled(false); m_Controls.Logfilter->setEnabled(false); + m_Controls.BModeMethod->setEnabled(false); m_Controls.buttonApplyBModeFilter->setEnabled(false); m_Controls.CutoffAbove->setEnabled(false); m_Controls.CutoffBelow->setEnabled(false); - m_Controls.Cutoff->setEnabled(false); + m_Controls.CutoffBeforeBF->setEnabled(false); m_Controls.buttonApplyCropFilter->setEnabled(false); - + m_Controls.BPSpeedOfSound->setEnabled(false); m_Controls.buttonApplyBandpass->setEnabled(false); + m_Controls.Partial->setEnabled(false); + m_Controls.boundHigh->setEnabled(false); + m_Controls.boundLow->setEnabled(false); m_Controls.BFAlgorithm->setEnabled(false); m_Controls.DelayCalculation->setEnabled(false); m_Controls.ImageType->setEnabled(false); m_Controls.Apodization->setEnabled(false); m_Controls.UseBP->setEnabled(false); - m_Controls.UseGPU->setEnabled(false); + + #ifdef PHOTOACOUSTICS_USE_GPU + m_Controls.UseGPUBf->setEnabled(false); + m_Controls.UseGPUBmode->setEnabled(false); + #endif + m_Controls.BPhigh->setEnabled(false); m_Controls.BPlow->setEnabled(false); m_Controls.BPFalloff->setEnabled(false); m_Controls.UseImageSpacing->setEnabled(false); m_Controls.ScanDepth->setEnabled(false); m_Controls.Pitch->setEnabled(false); m_Controls.ElementCount->setEnabled(false); m_Controls.SpeedOfSound->setEnabled(false); m_Controls.Samples->setEnabled(false); m_Controls.Lines->setEnabled(false); m_Controls.Angle->setEnabled(false); m_Controls.buttonApplyBeamforming->setEnabled(false); } void PAImageProcessing::UseImageSpacing() { if (m_Controls.UseImageSpacing->isChecked()) { m_Controls.ScanDepth->setDisabled(true); } else { m_Controls.ScanDepth->setEnabled(true); } } +#include + void BeamformingThread::run() { - mitk::Image::Pointer resultImage; - mitk::PhotoacousticImage::Pointer filterbank = mitk::PhotoacousticImage::New(); + mitk::Image::Pointer resultImage = mitk::Image::New(); + mitk::Image::Pointer resultImageBuffer; + std::string errorMessage = ""; std::function progressHandle = [this](int progress, std::string progressInfo) { emit updateProgress(progress, progressInfo); }; - resultImage = filterbank->ApplyBeamforming(m_InputImage, m_BFconfig, m_Cutoff, progressHandle); + resultImageBuffer = m_FilterBank->ApplyBeamforming(m_InputImage, m_BFconfig, errorMessage, progressHandle); + mitk::ImageReadAccessor copy(resultImageBuffer); + + resultImage->Initialize(resultImageBuffer); + resultImage->SetSpacing(resultImageBuffer->GetGeometry()->GetSpacing()); + resultImage->SetImportVolume(const_cast(copy.GetData()), 0, 0, mitk::Image::CopyMemory); - emit result(resultImage); + emit result(resultImage); + emit message(errorMessage); } -void BeamformingThread::setConfig(mitk::BeamformingFilter::beamformingSettings BFconfig) +void BeamformingThread::setConfig(mitk::BeamformingSettings BFconfig) { m_BFconfig = BFconfig; } void BeamformingThread::setInputImage(mitk::Image::Pointer image) { m_InputImage = image; } -void BeamformingThread::setCutoff(int cutoff) -{ - m_Cutoff = cutoff; -} - void BmodeThread::run() { mitk::Image::Pointer resultImage; - mitk::PhotoacousticImage::Pointer filterbank = mitk::PhotoacousticImage::New(); - resultImage = filterbank->ApplyBmodeFilter(m_InputImage, m_Method, m_UseLogfilter, m_ResampleSpacing); + resultImage = m_FilterBank->ApplyBmodeFilter(m_InputImage, m_Method, m_UseGPU, m_UseLogfilter, m_ResampleSpacing); emit result(resultImage); } -void BmodeThread::setConfig(bool useLogfilter, double resampleSpacing, mitk::PhotoacousticImage::BModeMethod method) +void BmodeThread::setConfig(bool useLogfilter, double resampleSpacing, mitk::PhotoacousticImage::BModeMethod method, bool useGPU) { m_UseLogfilter = useLogfilter; m_ResampleSpacing = resampleSpacing; m_Method = method; + m_UseGPU = useGPU; } void BmodeThread::setInputImage(mitk::Image::Pointer image) { m_InputImage = image; } void CropThread::run() { mitk::Image::Pointer resultImage; - mitk::PhotoacousticImage::Pointer filterbank = mitk::PhotoacousticImage::New(); - resultImage = filterbank->ApplyCropping(m_InputImage, m_CutAbove, m_CutBelow, 0, 0, 0, m_InputImage->GetDimension(2) - 1); + resultImage = m_FilterBank->ApplyCropping(m_InputImage, m_CutAbove, m_CutBelow, 0, 0, m_CutSliceFirst, m_CutSliceLast); emit result(resultImage); } -void CropThread::setConfig(unsigned int CutAbove, unsigned int CutBelow) +void CropThread::setConfig(unsigned int CutAbove, unsigned int CutBelow, unsigned int CutSliceFirst, unsigned int CutSliceLast) { m_CutAbove = CutAbove; m_CutBelow = CutBelow; + m_CutSliceLast = CutSliceLast; + m_CutSliceFirst = CutSliceFirst; } void CropThread::setInputImage(mitk::Image::Pointer image) { m_InputImage = image; } void BandpassThread::run() { mitk::Image::Pointer resultImage; - mitk::PhotoacousticImage::Pointer filterbank = mitk::PhotoacousticImage::New(); - resultImage = filterbank->BandpassFilter(m_InputImage, m_RecordTime, m_BPHighPass, m_BPLowPass, m_TukeyAlpha); + resultImage = m_FilterBank->BandpassFilter(m_InputImage, m_RecordTime, m_BPHighPass, m_BPLowPass, m_TukeyAlpha); emit result(resultImage); } void BandpassThread::setConfig(float BPHighPass, float BPLowPass, float TukeyAlpha, float recordTime) { m_BPHighPass = BPHighPass; m_BPLowPass = BPLowPass; m_TukeyAlpha = TukeyAlpha; m_RecordTime = recordTime; } void BandpassThread::setInputImage(mitk::Image::Pointer image) { m_InputImage = image; } diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessing.h b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessing.h index 42270dd4c7..d20b78b3ae 100644 --- a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessing.h +++ b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessing.h @@ -1,182 +1,254 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ - #ifndef PAImageProcessing_h #define PAImageProcessing_h #include + #include #include #include #include "ui_PAImageProcessingControls.h" #include "mitkPhotoacousticBeamformingFilter.h" +#include "mitkPhotoacousticBeamformingSettings.h" Q_DECLARE_METATYPE(mitk::Image::Pointer) Q_DECLARE_METATYPE(std::string) +/*! +* \brief Plugin implementing an interface for the Photoacoustic Algorithms Module +* +* Beamforming, Image processing as B-Mode filtering, cropping, resampling, as well as batch processing can be performed using this plugin. +*/ + class PAImageProcessing : public QmitkAbstractView { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: static const std::string VIEW_ID; PAImageProcessing(); protected slots: - /// \brief Called when the user clicks the GUI button - - void UpdateBounds(); + void UpperSliceBoundChanged(); + void LowerSliceBoundChanged(); + void SliceBoundsEnabled(); void UseResampling(); void UseLogfilter(); void SetResampling(); void UseImageSpacing(); void UpdateImageInfo(); - void UpdateRecordTime(mitk::Image::Pointer image); + /** \brief Method called when the beamforming thread finishes; + * it adds the image to a new data node and registers it to the worbench's data storage + */ void HandleBeamformingResults(mitk::Image::Pointer image); + /** \brief Beamforming is being performed in a separate thread to keep the workbench from freezing. + */ void StartBeamformingThread(); + /** \brief Method called when the B-mode filter thread finishes; + * it adds the image to a new data node and registers it to the worbench's data storage + */ void HandleBmodeResults(mitk::Image::Pointer image); + /** \brief B-mode filtering is being performed in a separate thread to keep the workbench from freezing. + */ void StartBmodeThread(); + /** \brief Method called when the Cropping thread finishes; + * it adds the image to a new data node and registers it to the worbench's data storage + */ void HandleCropResults(mitk::Image::Pointer image); + /** \brief Cropping is being performed in a separate thread to keep the workbench from freezing. + */ void StartCropThread(); + /** \brief Method called when the bandpass thread finishes; + * it adds the image to a new data node and registers it to the worbench's data storage + */ void HandleBandpassResults(mitk::Image::Pointer image); + /** \brief Bandpassing is being performed in a separate thread to keep the workbench from freezing. + */ void StartBandpassThread(); void UpdateProgress(int progress, std::string progressInfo); + void PAMessageBox(std::string message); void BatchProcessing(); void UpdateSaveBoxes(); + void ChangedSOSBandpass(); + void ChangedSOSBeamforming(); + protected: virtual void CreateQtPartControl(QWidget *parent) override; virtual void SetFocus() override; - /// \brief called by QmitkFunctionality when DataManager's selection has changed + /** \brief called by QmitkFunctionality when DataManager's selection has changed. + * On a change some parameters are internally updated to calculate bounds for GUI elements as the slice selector for beamforming or + * the bandpass filter settings. + */ virtual void OnSelectionChanged( berry::IWorkbenchPart::Pointer source, const QList& nodes ) override; + /** \brief Instance of the GUI controls + */ Ui::PAImageProcessingControls m_Controls; float m_ResampleSpacing; bool m_UseLogfilter; std::string m_OldNodeName; - mitk::BeamformingFilter::beamformingSettings BFconfig; + /** \brief The settings set which is used for beamforming, updated through this class. + */ + mitk::BeamformingSettings BFconfig; + /** \brief Method for updating the BFconfig by using a selected image and the GUI configuration. + */ void UpdateBFSettings(mitk::Image::Pointer image); void EnableControls(); void DisableControls(); + + /** \brief Class through which the filters are called. + */ + mitk::PhotoacousticImage::Pointer m_FilterBank; }; class BeamformingThread : public QThread { Q_OBJECT void run() Q_DECL_OVERRIDE; signals: void result(mitk::Image::Pointer); void updateProgress(int, std::string); + void message(std::string); public: - void setConfig(mitk::BeamformingFilter::beamformingSettings BFconfig); + void setConfig(mitk::BeamformingSettings BFconfig); void setInputImage(mitk::Image::Pointer image); - void setCutoff(int cutoff); + void setFilterBank(mitk::PhotoacousticImage::Pointer filterBank) + { + m_FilterBank = filterBank; + } + protected: - mitk::BeamformingFilter::beamformingSettings m_BFconfig; + mitk::BeamformingSettings m_BFconfig; mitk::Image::Pointer m_InputImage; int m_Cutoff; + + mitk::PhotoacousticImage::Pointer m_FilterBank; }; class BmodeThread : public QThread { Q_OBJECT void run() Q_DECL_OVERRIDE; signals: void result(mitk::Image::Pointer); public: enum BModeMethod { ShapeDetection, Abs }; - void setConfig(bool useLogfilter, double resampleSpacing, mitk::PhotoacousticImage::BModeMethod method); + void setConfig(bool useLogfilter, double resampleSpacing, mitk::PhotoacousticImage::BModeMethod method, bool useGPU); void setInputImage(mitk::Image::Pointer image); + void setFilterBank(mitk::PhotoacousticImage::Pointer filterBank) + { + m_FilterBank = filterBank; + } + protected: mitk::Image::Pointer m_InputImage; mitk::PhotoacousticImage::BModeMethod m_Method; bool m_UseLogfilter; double m_ResampleSpacing; + bool m_UseGPU; + + mitk::PhotoacousticImage::Pointer m_FilterBank; }; class CropThread : public QThread { Q_OBJECT void run() Q_DECL_OVERRIDE; signals: void result(mitk::Image::Pointer); public: - void setConfig(unsigned int CutAbove, unsigned int CutBelow); + void setConfig(unsigned int CutAbove, unsigned int CutBelow, unsigned int CutSliceFirst, unsigned int CutSliceLast); void setInputImage(mitk::Image::Pointer image); + void setFilterBank(mitk::PhotoacousticImage::Pointer filterBank) + { + m_FilterBank = filterBank; + } protected: mitk::Image::Pointer m_InputImage; unsigned int m_CutAbove; unsigned int m_CutBelow; + unsigned int m_CutSliceLast; + unsigned int m_CutSliceFirst; + + mitk::PhotoacousticImage::Pointer m_FilterBank; }; class BandpassThread : public QThread { Q_OBJECT void run() Q_DECL_OVERRIDE; signals: void result(mitk::Image::Pointer); public: void setConfig(float BPHighPass, float BPLowPass, float TukeyAlpha, float recordTime); void setInputImage(mitk::Image::Pointer image); + void setFilterBank(mitk::PhotoacousticImage::Pointer filterBank) + { + m_FilterBank = filterBank; + } protected: mitk::Image::Pointer m_InputImage; float m_BPHighPass; float m_BPLowPass; float m_TukeyAlpha; float m_RecordTime; + + mitk::PhotoacousticImage::Pointer m_FilterBank; }; #endif // PAImageProcessing_h diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessingControls.ui b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessingControls.ui index bbc2c814b3..fcd6e415c8 100644 --- a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessingControls.ui +++ b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessingControls.ui @@ -1,960 +1,991 @@ PAImageProcessingControls 0 0 382 - 1217 + 1278 0 0 QmitkTemplate <html><head/><body><p><span style=" font-weight:600;">Batch Processing</span></p></body></html> Start Batch Processing Bandpass true Crop true Save true Save true Save Beamform true BMode true Save true <html><head/><body><p><span style=" font-weight:600;">B-mode Filter Settings</span></p></body></html> + + + + Absolute Filter + + + + Absolute Filter + + + + + Envelope Detection + + + + Do Resampling - - - - - - - Absolute Filter - - - - - Envelope Detection - - + + true + 0 0 13 0 11 + + 3 + 0.010000000000000 1.000000000000000 0.010000000000000 - 0.100000000000000 + 0.075000000000000 - [mm] Depth Spacing + [mm] Resampled Depth Spacing Add Logfilter + + + + Use GPU + + + QLabel { color: rgb(255, 0, 0) } <html><head/><body><p align="center"><span style=" font-size:10pt; font-weight:600;">Please select an image!</span></p></body></html> 0 0 Do image processing Apply B-mode Filter Qt::Horizontal <html><head/><body><p><span style=" font-weight:600;">Bandpass Filter Settings</span></p></body></html> QLayout::SetDefaultConstraint 0 0 0 3 0.010000000000000 200.000000000000000 15.000000000000000 [MHz] f High Pass [MHz] f Low Pass 0 0 3 200.000000000000000 - Thukey window alpha + Tukey window alpha 1 200.000000000000000 3000.000000000000000 5.000000000000000 - 1480.000000000000000 + 1540.000000000000000 [m/s] Speed of Sound 2 1.000000000000000 0.100000000000000 0.500000000000000 <html><head/><body><p align="center"><span style=" font-size:10pt; font-weight:600; color:#ff0000;">Please select an image!</span></p></body></html> Apply Bandpass Qt::Horizontal <html><head/><body><p><span style=" font-weight:600;">Crop Filter Settings</span></p></body></html> - - - + + + 99999 - - 5 - - 165 + 10 - - + + Cut Top - - + + + + Cut Bottom + + + + + 99999 - - 10 + + 5 - - - - - - Cut Bottom + + 165 <html><head/><body><p align="center"><span style=" font-size:10pt; font-weight:600; color:#ff0000;">Please select an image!</span></p></body></html> Apply Crop Filer Qt::Horizontal <html><head/><body><p><span style=" font-weight:600;">Beamforming Filter Settings</span></p></body></html> 5 2 Delay Calculation Auto Get Depth true Apply Beamforming Beamforming Method [mm] Scan Depth 0 0 - 2 + 3 0.010000000000000 9.000000000000000 0.050000000000000 0.300000000000000 Transducer Elements 0 0 4 300.000000000000000 0.100000000000000 50.000000000000000 [mm] Transducer Pitch 0 0 64 1024 128 128 0 0 256 16384 256 2048 0 0 64 2048 128 256 Samples Reconstruction Lines true 0 0 100 0 - + 0 0 900 10 0 - - - - Cutoff Upper Voxels - - - 0 0 DAS DMAS + + + sDMAS + + 0 0 + + Quad. Approx. + Quad. Approx. Spherical Wave 0 0 PA Image US Image Image Type 0 0 Von Hann Hamming Box Apodization 0 0 1 200.000000000000000 3000.000000000000000 5.000000000000000 - 1480.000000000000000 + 1540.000000000000000 [m/s] Speed of Sound false 99999 minimal beamformed slice min false 99999 10 Maximal beamformed slice max select slices - + Compute On GPU true true Auto Use Bandpass 0 0 1 1.000000000000000 180.000000000000000 27.000000000000000 [°] Element Angle + + + + Cutoff Upper Voxels + + + + + + + <html><head/><body><p align="center"><span style=" font-size:10pt; font-weight:600; color:#ff0000;">Please select an image!</span></p></body></html> + + + diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.simulation/documentation/UserManual/Manual.dox b/Plugins/org.mitk.gui.qt.photoacoustics.simulation/documentation/UserManual/Manual.dox deleted file mode 100644 index e9e31e8451..0000000000 --- a/Plugins/org.mitk.gui.qt.photoacoustics.simulation/documentation/UserManual/Manual.dox +++ /dev/null @@ -1,12 +0,0 @@ -/** -\page org_mitk_gui_qt_photoacousticsimulation Photoacoustic Tissue Generator - -\imageMacro{icon.png,"Icon of Photoacousticsimulation", 2.00} - -\tableofcontents - -\section org_mitk_gui_qt_photoacousticsimulationOverview Overview - -TODO Describe this!! - -*/ diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.simulation/documentation/UserManual/icon.xpm b/Plugins/org.mitk.gui.qt.photoacoustics.simulation/documentation/UserManual/icon.xpm deleted file mode 100644 index d6f2f2a34b..0000000000 --- a/Plugins/org.mitk.gui.qt.photoacoustics.simulation/documentation/UserManual/icon.xpm +++ /dev/null @@ -1,203 +0,0 @@ -/* XPM */ -static char * icon_xpm[] = { -"128 128 72 1", -" c None", -". c #484848", -"+ c #2E2E2E", -"@ c #272727", -"# c #242424", -"$ c #202020", -"% c #171717", -"& c #1C1C1C", -"* c #1A1A1A", -"= c #191919", -"- c #222222", -"; c #292929", -"> c #404040", -", c #313131", -"' c #1B1B1B", -") c #0E0E0E", -"! c #070707", -"~ c #000000", -"{ c #0A0A0A", -"] c #111111", -"^ c #282828", -"/ c #2D2D2D", -"( c #050505", -"_ c #010101", -": c #0D0D0D", -"< c #151515", -"[ c #1E1E1E", -"} c #080808", -"| c #030303", -"1 c #020202", -"2 c #1D1D1D", -"3 c #0C0C0C", -"4 c #2F2F2F", -"5 c #181818", -"6 c #161616", -"7 c #232323", -"8 c #262626", -"9 c #212121", -"0 c #121212", -"a c #040404", -"b c #323232", -"c c #252525", -"d c #0B0B0B", -"e c #3C3C3C", -"f c #131313", -"g c #090909", -"h c #1F1F1F", -"i c #060606", -"j c #2C2C2C", -"k c #141414", -"l c #3A3A3A", -"m c #2A2A2A", -"n c #333333", -"o c #3B3B3B", -"p c #3D3D3D", -"q c #101010", -"r c #373737", -"s c #0F0F0F", -"t c #3E3E3E", -"u c #343434", -"v c #353535", -"w c #414141", -"x c #383838", -"y c #303030", -"z c #393939", -"A c #424242", -"B c #2B2B2B", -"C c #454545", -"D c #3F3F3F", -"E c #4D4D4D", -"F c #4B4B4B", -"G c #363636", -" ", -" .+@#$%&*=-;> ", -" ,')!~~~~~~~~~~~~~{]^ ", -" /*](~~~~~~~~~__~~~~_~~~~_:<[ ", -" ^}|~_~~~~___~~~__~~~_~~_~~~~~11* ", -" ^!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~2 ", -" '3~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(% ", -" 4!_~~~_~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~_~~~15 ", -" -~~~~_~~~~~~~~_(!}65&[7892&0}}a_~~~~~~~~~~~~~{b ", -" +)~~~~~~_~~~~~3'$ c$d~~~~~~~~~~~~~6 ", -" c~~~~~~~~~~~1[e ef_~~~~~~~~~~~g ", -" h~~_~~~~~~~}2 f!_~~~~~~~~~1 ", -" %_~~~~~~~~38 -i~~_~~~~~~(j ", -" k~~~~~~~~~7 [~~_~~~~~~_b ", -" =~~~~~~~_3l @g~~~~~~~~~m ", -" ;1~_~~~~~9 &_~~~~~~~( ", -" e_~~~~~~1n b1~~~~~~~a ", -" i~~~~~~{o p{~_~~~~~} ", -" f~~~~~~: q~~~~~_~k ", -" ,~~~~~~: q~~~~~_~/ ", -" !~~~~~g 0~~~~~~i ", -" <~~~~~|o :~~~~~~6 ", -" |~~~~~r (~~~~~1 ", -" 6~~~~~& g~~~~~] ", -" (~~~~! 4a_~~_1r ", -" 2~~~~~j h~~~~~s ", -" ~~~~~2 k~~~~~t ", -" *~~~~{ g~~~~s ", -" a~~~~7 8_~_~| ", -" a~~~! 3~~__2 ", -" *~~~~2 u~~~~!q@ ", -" q~~~~~1 _~_~~_( ", -" i~_~~~~, [~~~~~_| ", -" a~~~~~~& &~~~~_~18 ", -" c_~~~~~~v >~~~~~_~5 ", -" h_~~~~~~ |_~~_~~f ", -" k_~__~~) 5~~_~~_( ", -" d~~_~~~h ^~_~~~~1 ", -" 51_~~~~, w~~~~~|7 ", -" %~~{q) ^9/{~! ", -" d~| =~( ", -" i~} _11_1_ '~a ", -" !~d ~~~~~~~~~~~~~~~~~ ;_| ", -" !~] ~~~~~~~~~~~~~~~~~~~~~ /11 ", -" i~< i~~~~~~~ ~~~~~~~~ x11# ", -" i~5 ~~~~~~ ~~~~~~ w11 ", -" |_* ~~~~~~~ ~~~~~~ t11 ", -" a~' ~~~~~~ ~~~~ y11+ ", -" 9-y1~* z@ ~~~~~ ~~~a 8:<-u j1~3}i7 ", -" $~~~~~5 61~~_# ~~~~~ ~~~~ 6~~~~~% h_~~_~d ", -" 6~_~_~5 f~~~_~~w ~~~~ ~~~~ ~~~~~~_n '~~~~~} ", -" =~~_~_5 i~~~~~~4 ~~~~ ~~~~ A~~~~~~~[ %~___~) ", -" *~~~~~5 b@'~__~~~~7 ~~~~ ~~~~ ;~~~~~~~~~i9A<~~_~~s ", -" =~~~~~{'}~~~~~~~~~~[ ~~~~ ~~~ 8~~~~~~~~~~~~~_~_~~f ", -" &~~~~~~~_~~~~~~~~~~k ~~~ ~~~ [~~~~_~~~~~_~~~~~~~& ", -" c~~~~~~~~~~~~~~~~~~| ~~~~ ~~~ k~~~~~~~~~~~~~~~~~~2 ", -" B_~~~~~~~~~~~~~~~~~~ ~~~ ~~~ 3~~~~~~~~~~~~~~~~~~* ", -" B|~~~~~~~~~~~~~~~~~~ ~~~ ~~~ |~~~~~~~~~~~~~~~~~~[ ", -" a~~~~~~~~~~~~~~~~~~e~~~ ~~~ ~~~~~~~~~~~~~~~~~~~[ ", -" [_~~~~~~~~~~~~~~~~~~$|~~ ~~m~~~~~~~~~~~~~~~~~~~} ", -" |~~~~~~~~~~~~~~~~~~~ka~ ~~-~~~~~~~~~~~~~~~~_~_~* ", -" h~_~~~~~~~~~~~~~~~~~~f}~ ~|9~~~~~~~~~~~~~~~~~~~~~ ", -" |~~~~~~~~~~~~~~~~~~~~0)~ ~(*~~~~~~~~~~~~~~~~~~~~~= ", -" ^~~~~~~~~~~~~~~~~~~~~~qs_ ~if~~~~~~~~~~~~~~~~~~~~~} ", -" <~~~~~~~~~~~~~~~~~~~~_d3_ ~!q~~~~~~~~~~~~~~~~~~~~~! ", -" ]~~~~~~~~~~~~~~~~~~~~~{{_ ~~ ~~_~~~_~~~ ~{]~~~~~~~~~~~~~~~~~~~~~( ", -" h~~~~~~~~~~~~~~~~~~~__{s1 ~~~~~~~~~~~~~~~~~~~~~~~ ~:]~~~~~~~~~~~~~~~~~~~~~i ", -" &~~~~~~~~~~~~~~~~~~~~_i=~ ~~~~~~~~~~~1 _~~ _~~~~ _)0~~~~~~~~~~~~~~~~~~~~~i ", -" 2~~~~~~~~~~~~~~~~~~~~_|*~ ~~~ ~~ ~~ ~~~ _d:_~~~~~~~~~~~~~~~~~~~~} ", -" 9~~~~~~~~~~~~~~~~~~~~~~%_ ~~ ~~ ~~ ~~ _{d_~~~~~~~~~~~~~~~~~~~~{ ", -" n~~~~~~~~~~~~~~~~~~~~~~'~ ~~~ ~~ ~~~ ~~~ _fg~~~~~~~~~~~~~~~~~~~~~s ", -" C~~~~~~~~~~~~~~~~~~~~~~#~ ~~ ~~ ~~ ~~ ~[i_~~~~~~~~~~~~~~~~~~~~k ", -" D~~~~~~~~~~~~~~~~~~~~~~'(_ ~~ ~~ ~~ ~~ ~2~~~~~~~~~~~~~~~~~~~~~~k ", -" ~~~~~~~~~~~~~~~~~~~~~~fg~ ~~~ ~~~ ~~ ~~~ ~~*~~~~~~~~~~~~~~~~~~~~~~5 ", -" ~~~~~~~~~~~~~~~~~~~~_~)q~ ~~ ~~ ~~_ ~~ _~9~~~~~~~~~~~~~~~~~~~~~~B ", -" _~~~~~~~~~~~~~~~~~~~~_g&~~ ~~~ ~~~~~~~~ ~~~ _~7~__~~~~~~~~~~~~~~~~~~~l ", -" g~~~~~~~~~~~~~~~~~~~~_~8~~ ~~~ ~~~~~~~~ ~~ ~~i7~~~~~~~~~~~~~~~~~~~~~~> ", -" %~~~~~~~~~~~~~~~~~~~__~9~~~ ~~ ~~~~~~~ ~~~ ~~~ ]~~~~~~~~~~~~~~~~~~~~~~ ", -" '~~~~~~~~~~~~~~~~~~~~~~#~~~ ~~~ ~~ ~1 ~~~ ~~~ g~~~~~~~~~~~~~~~~~~~~~1 ", -" #~~~~~~~~~~~~~~~~~~~__~B|~~~ ~~~ ~~~~1 ~~~ ~~~ i~~~~~~~~~~~~~~~~~~~~~{ ", -" v~~~~~~~~~~~~~~~~~~~__~9 ~~~ ~~ ~~~~1 ~~~ ~~~ _~~~~~~~~~~~~~~~~~~~~~0 ", -" E~~~~~~~~~~~~~~~~~~~~~~{ ~~~ ~~~ ~~~~ ~~ ~~~~ F~~~~~~~~~~~~~~~~~~~~~~$ ", -" i_~~~~~~~~~~~~~~~~~~~~( ~~~ ~~ ~~~~ ~~~ ~~~ v~~~~~~~~~~~~~~~~~~~~~~G ", -" %~~~~~~~~~~~~~~~~~~~~~| ~~~~ ~~_~~~~1~~ ~~~ 8~_~~~~~~~~~~~~~~~~~~~{ ", -" 7~~~~~~~~~~~~~~~~~~~~~~ ~~~ _~~~~~~_~~ ~~~ 7~~~~~~~~~~~~~~~~~~_~_h ", -" g~~~~~~~~~~~~~~~~~~~~~4 ~~~~ ~~~~~~~~~~ ~~~ 2~_~~~~~~~~~~~~~~~~~~i ", -" y~_~~~~~~~~~~~~~~~~~~~9 ~~~ ~~~~~~~~~~_ ~~~ 0~~~~~~~~~~~~~~~~~~_~@ ", -" c~~~~~~~~~~~~~~~~~~~~9 ~~~~ ~~~ ~~_ ~~~ }~~~~~~~~~~~~~~~~~~~2 ", -" :~~~~~~~~~~~~~~~~~~~[ ~~~ ~~ __~ ~~_ ~~~ _~~~~~~~~~~~~~~~~~~~9 ", -" <~~_~~~~~~~~~~~~~~~~f ~~~~ ~~ ~i ~ ~~_ ~~~ _~~~~~~~~~_~~~~_~_~~~ ", -" 6~~__~__~~~~~~~~~~~~s ~~~ ~~~~~|~~~~ ~~~ 1~~~~~~~~~~_~~~1ki_3 ", -" 0sh2:~~~~~~~~~~~~~~: ~~~ ~~~~~~~~~~ ~~~ b_~~~~~~~~~~~~{5 7 ", -" v2!~~~~~~~~~~~3 ~~~ ~~__~~~~~~ ~~~ ~~~~~~~dsds#u ", -" >y+l'~~~~~_$ ~~~ ~~1 ~~~_~~ ~~ #___~~s ", -" 6diq09 ~~~ ~~1 ~ ~ ~~ ~~~ #$=[ ", -" _~~ ~~1 ~ ~ ~~ _~~ ", -" ~~ ~~_ ~ ~1~~ ~~_ ", -" ~~ ~~~ ~ ~ ~~ ~~_ ", -" ~~ ~~~ ~ ~ ~~ ~~_ ", -" ~~_ ~~~ ~ ~ ~~ ~~~ ", -" ~~~ _~~~ ~ ~ ~~ ~~~ ", -" ~~~~ 1~~ ~ ~ ~~ ~~~~ ", -" ~~~~~~~~~~_~~~~~~~_~~~~~~~ ", -" ~~~~~~~~~~~~~~~~~~~~~~~~~~ ", -" ~~~~~~~~~~~~~~~~~~~~~~_1 ", -" 6~~~~~~~~~~~~~~~~~~~~q ", -" ]~~~~~~~~~~~~~~~~~~~~q ", -" ~~~~~~~~~~~~~~~~~~~~~d ", -" B~~~~~~~~~~~~~~~~~~~~d ", -" #~~~~~~~~~~~~~~~~~~~_6 ", -" _~~~~~~~~~~~~~~~~~~~| ", -" _~~~~~~~~~~~~~~~~~~_6 ", -" ^_~~~~~~~~~~~~~~~~~~_% ", -" |~~~~~~~~~~~~_1~1~~~1 ", -" 1~~~~~~~~~~~~~~~~~~_& ", -" @_~~~~~~~~~~~~~~~~~~_% ", -" |~~~~~~~~~~~~~~~~~~~_ ", -" dggggggggggggggggggg% ", -" #_~~~~~~~~~~~~~~~~~~~' ", -" =~~~~~~~~~~~~~~__~~~1 ", -" f~~~~~~~~~~~~:a(1~~{ ", -" *~~~~~~~~~~~~~~~~] ", -" 71~~~~~~~~~~~~~q ", -" [_~~~~~~~~~~_9 ", -" 7~~~~~~~~~1h ", -" @~~~~~~~~0 ", -" j##h1]7B ", -" "}; diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.simulation/documentation/doxygen/modules.dox b/Plugins/org.mitk.gui.qt.photoacoustics.simulation/documentation/doxygen/modules.dox deleted file mode 100644 index 1032079a00..0000000000 --- a/Plugins/org.mitk.gui.qt.photoacoustics.simulation/documentation/doxygen/modules.dox +++ /dev/null @@ -1,16 +0,0 @@ -/** - \defgroup org_mitk_gui_qt_photoacousticsimulation org.mitk.gui.qt.photoacousticsimulation - \ingroup MITKPlugins - - \brief Describe your plugin here. - -*/ - -/** - \defgroup org_mitk_gui_qt_photoacousticsimulation_internal Internal - \ingroup org_mitk_gui_qt_photoacousticsimulation - - \brief This subcategory includes the internal classes of the org.mitk.gui.qt.photoacousticsimulation plugin. Other - plugins must not rely on these classes. They contain implementation details and their interface - may change at any time. We mean it. -*/