diff --git a/Documentation/Doxygen/3-DeveloperManual/Starting/SettingUpMITK/BuildInstructions.dox b/Documentation/Doxygen/3-DeveloperManual/Starting/SettingUpMITK/BuildInstructions.dox
index c8fbcc7f30..dc44f28335 100644
--- a/Documentation/Doxygen/3-DeveloperManual/Starting/SettingUpMITK/BuildInstructions.dox
+++ b/Documentation/Doxygen/3-DeveloperManual/Starting/SettingUpMITK/BuildInstructions.dox
@@ -1,236 +1,236 @@
/**
\page BuildInstructionsPage Build Instructions
\tableofcontents
\section BuildInstructions_Introduction Introduction
The CMake-based build system of MITK supports a "superbuild" process,
meaning that it will download, configure, and build all required third-party
libraries (except Qt) automatically. These instructions will show you how to use
the MITK superbuild.
\note This page explains explicitly how to build MITK itself. If you want to
create your own project based on MITK, the process described below is completely
automated. Please see \ref HowToNewProject.
For more advanced users, the last sections explains how to inject custom build
libraries into the superbuild process.
\section BuildInstructions_Prerequisites Prerequisites
You need:
-# Git (there are also numerous third-party graphical
clients available). We recommend using Git, but see below for a way how to
get the current source code without using it.
-# CMake (version \minimumCMakeVersion or higher)
-# Qt \minimumQt5Version if you plan to develop Qt-based
applications
-# If you are using macOS you need an XCode installation and the
Command Line Tools as it provides the neccessary compilers and SDKs
To build MITK on Linux, install the following packages, e. g. with APT:
\code{.unparsed}
sudo apt install build-essential doxygen git graphviz libfreetype6-dev libglu1-mesa-dev libssl-dev libtiff5-dev libwrap0-dev libxcomposite1 libxcursor1 libxdamage-dev libxi-dev libxkbcommon-x11-0 libxt-dev mesa-common-dev
\endcode
For the optional and experimental (!) Python integration, install NumPy and SimpleITK v1.x, e. g.:
\code{.unparsed}
sudo apt install python3-numpy python3-pip
-pip3 install SimpleITK==1.*
+pip3 install SimpleITK
\endcode
\section BuildInstructions_Qt A note about Qt
As we do not provide Qt in the MITK superbuild you need to install Qt manually.
The Qt Company provides online installers
for all supported platforms.
We highly recommend to install Qt to the default location of the installer as it will allow MITK to automatically find Qt without any further action needed.
Make sure to also select the following required components:
- QtWebEngine
- QtScript
On Windows, the Qt installer offers a welcome and straight forward way to install OpenSSL.
You find it under the Tools node.
\section BuildInstructions_Get_Source Get a source tree
Since MITK is under active development we recommend to use Git to check out
the latest stable release from the homepage. If you decide to use the most
current nightly release, make sure to get a stable tree: Check the
MITK dashboard
before checking out. If the build tree is not clean, you can specify an
older revision for the checkout or get a stable tar ball from
www.mitk.org.
To clone MITK's current Git repository do:
\code
git clone https://phabricator.mitk.org/source/mitk.git MITK
\endcode
\section BuildInstructions_Build_With_CMake Build MITK with CMake
Create a new directory for the superbuild binary tree, change to it and call CMake:
In the shell (assuming your current directory is the same as the one where you
issued the git clone command):
\code
mkdir MITK-superbuild
cd MITK-superbuild
ccmake ../MITK
\endcode
If you use Windows or prefer to use the CMake GUI, start the CMake GUI and enter the
location of the source tree and binary tree, choose a suitable generator
and configure the project.
CMake will present you a couple of options, these are the most important ones:
- CMAKE_PREFIX_PATH The path to your Qt installation, e.g., C:/Qt/5.12.9/msvc2017_64 or /home/user/Qt/5.12.9/gcc_64
- MITK_USE_BLUEBERRY Build the BlueBerry application framework
- MITK_USE_Boost_LIBRARIES If you need binary Boost libraries,
specify them here.
- MITK_USE_OpenCV Build MITK code which depends on OpenCV (this
will download and build OpenCV 2.4)
- MITK_USE_Python3 Enables Python wrapping in MITK. This will also
configure ITK, VTK, and OpenCV (if enabled) to build Python wrappers.
- MITK_USE_Qt5 Build MITK code which depends on Qt 5
If you are satisfied with the configuration of your MITK superbuild, generate
the project files with CMake by pressing "Generate".
Linux and macOS users usually just enter "make" (optionally
supplying the number threads to be used for a parallel build):
\code
make -j6
\endcode
Windows users using Visual Studio can open the generated
MITK-superbuild.sln solution file in the MITK-superbuild
directory and start the build by building the BUILD_ALL project.
\section BuildInstructions_Customize Customize your MITK superbuild
The MITK superbuild configures MITK as well as all external libraries. The
build directories of these libraries, and of MITK itself are located inside
the MITK-superbuild directory. For example, the directory layout may
look like:
\code
MITK-superbuild
|- ep "external projects"
|-bin
|-lib
|-include
|-src
|- MITK-build
\endcode
To change the configuration of the MITK build itself, choose the MITK-build directory
as the binary directory in the CMake GUI (not the MITK-superbuild directory).
After generating the project files, build the MITK project by either issuing "make"
in the MITK-build directory (Linux, macOS), or by opening MITK-build/MITK.sln (Windows).
You may also change the configuration of any project configured via the
superbuild process. Make sure to also build the changed project and also the
projects which depend on it.
\section BuildInstructions_Running Running Applications
On Linux, just execute the application you want to run. MITK executables are
located in MITK-superbuild/MITK-build/bin
On Windows, the PATH environment variable must contain the directories
containing the third-party libraries. This is automatically done from Visual Studio.
For running the applications directly use the generated batch files in the
MITK-superbuild/MITK-build/bin.
\section BuildInstructions_Documentation Documentation
If you have the Doxygen documentation tool
installed, you get a new project (Visual Studio) or "make" target named "doc".
You can build this to generate the HTML documentation of MITK in the
Documentation/Doxygen directory of your MITK-build binary tree or in the
MITK_DOXYGEN_OUTPUT_DIR CMake variable (if specified).
\section BuildInstructions_Extending Extend MITK on your own (using the application framework BlueBerry)
Please see \ref NewPluginPage
\section BuildInstructions_As_Toolkit Use MITK in your own project (as a toolkit)
To use MITK in your external project, add the CMake command
find_package(MITK REQUIRED)
to your CMakeLists.txt and make use of
the CMake macros mitk_create_module()
and
mitk_create_executable()
provided by MITK.
Here is a very basic example CMakeLists.txt including MITK as a project:
\code
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
project(MyProject)
find_package(MITK 2021.10 REQUIRED)
add_executable(MyApp main.cpp)
target_link_libraries(MyApp MitkCore)
\endcode
with the main.ccp being
\code
#include
#include
int main()
{
MITK_INFO << "Hello world!";
return 0;
}
\endcode
\section BuildInstructions_Advanced_Customization Superbuild customization
You can inject pre-build third-party libraries into the MITK superbuild by
setting certain CMake variables before the first configure step. MITK will
then use these third-party libraries instead of downloading and building them
by itself. Note that you must take care of configuring those libraries with all options
MITK requires.
The variables listed below are provided for injecting third-party libraries.
Their occurrence in the CMake GUI or in ccmake may depend on specific
MITK_USE_* options set to ON. You may also use the variable names below without
the EXTERNAL_ prefix, for example when providing their values on a
command line call to CMake.
- EXTERNAL_BOOST_ROOT Set this variable to your custom Boost
installation
- EXTERNAL_CTK_DIR Set this variable to your CTK binary tree
(the directory containing the CTKConfig.cmake file)
- EXTERNAL_CableSwig_DIR Set this variable to your CableSwig
binary tree for Python wrapping (the directory containing the
CableSwigConfig.cmake file)
- EXTERNAL_DCMTK_DIR Set this variable to your DCMTK binary
tree (the directory containing the DCMTKConfig.cmake file)
- EXTERNAL_GDCM_DIR Set this variable to your GDCM binary
tree (the directory containing the GDCMConfig.cmake file)
- EXTERNAL_ITK_DIR Set this variable to your ITK binary tree
(the directory containing the ITKConfig.cmake file)
- EXTERNAL_OpenCV_DIR Set this variable to your OpenCV binary
tree (the directory containing the OpenCVConfig.cmake file)
- EXTERNAL_VTK_DIR Set this variable to your VTK binary tree
(the directory containing the VTKConfig.cmake file)
To set CMake options before the first configure step is invoked, supply them
on the command line, i.e.
\code
ccmake -DITK_DIR:PATH=/opt/ITK-release ../MITK
\endcode
*/
diff --git a/Modules/AppUtil/CMakeLists.txt b/Modules/AppUtil/CMakeLists.txt
index 4685d36486..e306674c8d 100644
--- a/Modules/AppUtil/CMakeLists.txt
+++ b/Modules/AppUtil/CMakeLists.txt
@@ -1,14 +1,14 @@
-set(qt5_depends Qt5|Widgets+WebEngine)
+set(qt5_depends Qt5|Widgets+WebEngineCore)
if(UNIX AND NOT APPLE)
set(qt5_depends "${qt5_depends}+X11Extras")
endif()
mitk_create_module(
PACKAGE_DEPENDS
PUBLIC CTK|CTKPluginFramework ${qt5_depends} Poco|Util
PRIVATE VTK|GUISupportQt
DEPENDS
PUBLIC qtsingleapplication
PRIVATE MitkCore
)
diff --git a/Modules/CEST/files.cmake b/Modules/CEST/files.cmake
index 8d29b23be8..0bf817db33 100644
--- a/Modules/CEST/files.cmake
+++ b/Modules/CEST/files.cmake
@@ -1,15 +1,23 @@
file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*")
set(CPP_FILES
mitkCESTImageNormalizationFilter.cpp
mitkCustomTagParser.cpp
mitkCESTImageDetectionHelper.cpp
mitkExtractCESTOffset.cpp
mitkCESTPropertyHelper.cpp
)
set(RESOURCE_FILES
1416.json
1485.json
1494.json
+ 1500.json
+ 1503.json
+ 1504.json
+ 1519.json
+ 1520.json
+ 1521.json
+ 1522.json
+ 1583.json
)
diff --git a/Modules/CEST/resource/1500.json b/Modules/CEST/resource/1500.json
new file mode 100644
index 0000000000..bfd1c3d0a9
--- /dev/null
+++ b/Modules/CEST/resource/1500.json
@@ -0,0 +1,28 @@
+{
+ "1500" : "revision_json",
+ "sWiPMemBlock.alFree[1]" : "AdvancedMode",
+ "sWiPMemBlock.alFree[2]" : "RecoveryMode",
+ "sWiPMemBlock.alFree[3]" : "DoubleIrrMode",
+ "sWiPMemBlock.alFree[4]" : "MtMode",
+ "sWiPMemBlock.alFree[5]" : "PreSatMode",
+ "sWiPMemBlock.alFree[6]" : "PreparationType",
+ "sWiPMemBlock.alFree[7]" : "PulseType",
+ "sWiPMemBlock.alFree[8]" : "SamplingType",
+ "sWiPMemBlock.alFree[9]" : "SpoilingType",
+ "sWiPMemBlock.alFree[10]" : "measurements",
+ "sWiPMemBlock.alFree[11]" : "NumberRFBlocks",
+ "sWiPMemBlock.alFree[12]" : "PulsesPerRFBlock",
+ "sWiPMemBlock.alFree[13]" : "PulseDuration",
+ "sWiPMemBlock.alFree[14]" : "DutyCycle",
+ "sWiPMemBlock.alFree[15]" : "RecoveryTime",
+ "sWiPMemBlock.alFree[16]" : "RecoveryTimeM0",
+ "sWiPMemBlock.alFree[17]" : "ReadoutDelay",
+ "sWiPMemBlock.alFree[18]" : "NumberPreSatPulses",
+ "sWiPMemBlock.adFree[1]" : "Offset",
+ "sWiPMemBlock.adFree[2]" : "B1Amplitude",
+ "sWiPMemBlock.adFree[3]" : "AdiabaticPulseMu",
+ "sWiPMemBlock.adFree[4]" : "AdiabaticPulseBW",
+ "sWiPMemBlock.adFree[5]" : "AdiabaticPulseLength",
+ "sWiPMemBlock.adFree[6]" : "AdiabaticPulseAmp",
+ "sWiPMemBlock.adFree[7]" : "OffsetPreSatPulse"
+}
diff --git a/Modules/CEST/resource/1503.json b/Modules/CEST/resource/1503.json
new file mode 100644
index 0000000000..4f5a1904ae
--- /dev/null
+++ b/Modules/CEST/resource/1503.json
@@ -0,0 +1,24 @@
+{
+ "1503" : "revision_json",
+ "sWiPMemBlock.alFree[1]" : "AdvancedMode",
+ "sWiPMemBlock.alFree[2]" : "RecoveryMode",
+ "sWiPMemBlock.alFree[3]" : "DoubleIrrMode",
+ "sWiPMemBlock.alFree[4]" : "MtMode",
+ "sWiPMemBlock.alFree[5]" : "PreparationType",
+ "sWiPMemBlock.alFree[6]" : "PulseType",
+ "sWiPMemBlock.alFree[7]" : "SamplingType",
+ "sWiPMemBlock.alFree[8]" : "SpoilingType",
+ "sWiPMemBlock.alFree[9]" : "measurements",
+ "sWiPMemBlock.alFree[10]" : "NumberRFBlocks",
+ "sWiPMemBlock.alFree[11]" : "PulsesPerRFBlock",
+ "sWiPMemBlock.alFree[12]" : "PulseDuration",
+ "sWiPMemBlock.alFree[13]" : "DutyCycle",
+ "sWiPMemBlock.alFree[14]" : "RecoveryTime",
+ "sWiPMemBlock.alFree[15]" : "RecoveryTimeM0",
+ "sWiPMemBlock.adFree[1]" : "Offset",
+ "sWiPMemBlock.adFree[2]" : "B1Amplitude",
+ "sWiPMemBlock.adFree[3]" : "AdiabaticPulseMu",
+ "sWiPMemBlock.adFree[4]" : "AdiabaticPulseBW",
+ "sWiPMemBlock.adFree[5]" : "AdiabaticPulseLength",
+ "sWiPMemBlock.adFree[6]" : "AdiabaticPulseAmp"
+}
diff --git a/Modules/CEST/resource/1504.json b/Modules/CEST/resource/1504.json
new file mode 100644
index 0000000000..3150f575fd
--- /dev/null
+++ b/Modules/CEST/resource/1504.json
@@ -0,0 +1,24 @@
+{
+ "1504" : "revision_json",
+ "sWiPMemBlock.alFree[1]" : "AdvancedMode",
+ "sWiPMemBlock.alFree[2]" : "RecoveryMode",
+ "sWiPMemBlock.alFree[3]" : "DoubleIrrMode",
+ "sWiPMemBlock.alFree[4]" : "MtMode",
+ "sWiPMemBlock.alFree[5]" : "PreparationType",
+ "sWiPMemBlock.alFree[6]" : "PulseType",
+ "sWiPMemBlock.alFree[7]" : "SamplingType",
+ "sWiPMemBlock.alFree[8]" : "SpoilingType",
+ "sWiPMemBlock.alFree[9]" : "measurements",
+ "sWiPMemBlock.alFree[10]" : "NumberRFBlocks",
+ "sWiPMemBlock.alFree[11]" : "PulsesPerRFBlock",
+ "sWiPMemBlock.alFree[12]" : "PulseDuration",
+ "sWiPMemBlock.alFree[13]" : "DutyCycle",
+ "sWiPMemBlock.alFree[14]" : "RecoveryTime",
+ "sWiPMemBlock.alFree[15]" : "RecoveryTimeM0",
+ "sWiPMemBlock.adFree[1]" : "Offset",
+ "sWiPMemBlock.adFree[2]" : "B1Amplitude",
+ "sWiPMemBlock.adFree[3]" : "AdiabaticPulseMu",
+ "sWiPMemBlock.adFree[4]" : "AdiabaticPulseBW",
+ "sWiPMemBlock.adFree[5]" : "AdiabaticPulseLength",
+ "sWiPMemBlock.adFree[6]" : "AdiabaticPulseAmp"
+}
diff --git a/Modules/CEST/resource/1519.json b/Modules/CEST/resource/1519.json
new file mode 100644
index 0000000000..5f34cbd684
--- /dev/null
+++ b/Modules/CEST/resource/1519.json
@@ -0,0 +1,24 @@
+{
+ "1519" : "revision_json",
+ "sWiPMemBlock.alFree[1]" : "AdvancedMode",
+ "sWiPMemBlock.alFree[2]" : "RecoveryMode",
+ "sWiPMemBlock.alFree[3]" : "DoubleIrrMode",
+ "sWiPMemBlock.alFree[4]" : "MtMode",
+ "sWiPMemBlock.alFree[5]" : "PreparationType",
+ "sWiPMemBlock.alFree[6]" : "PulseType",
+ "sWiPMemBlock.alFree[7]" : "SamplingType",
+ "sWiPMemBlock.alFree[8]" : "SpoilingType",
+ "sWiPMemBlock.alFree[9]" : "measurements",
+ "sWiPMemBlock.alFree[10]" : "NumberRFBlocks",
+ "sWiPMemBlock.alFree[11]" : "PulsesPerRFBlock",
+ "sWiPMemBlock.alFree[12]" : "PulseDuration",
+ "sWiPMemBlock.alFree[13]" : "DutyCycle",
+ "sWiPMemBlock.alFree[14]" : "RecoveryTime",
+ "sWiPMemBlock.alFree[15]" : "RecoveryTimeM0",
+ "sWiPMemBlock.adFree[1]" : "Offset",
+ "sWiPMemBlock.adFree[2]" : "B1Amplitude",
+ "sWiPMemBlock.adFree[3]" : "AdiabaticPulseMu",
+ "sWiPMemBlock.adFree[4]" : "AdiabaticPulseBW",
+ "sWiPMemBlock.adFree[5]" : "AdiabaticPulseLength",
+ "sWiPMemBlock.adFree[6]" : "AdiabaticPulseAmp"
+}
diff --git a/Modules/CEST/resource/1520.json b/Modules/CEST/resource/1520.json
new file mode 100644
index 0000000000..20d5894d8b
--- /dev/null
+++ b/Modules/CEST/resource/1520.json
@@ -0,0 +1,24 @@
+{
+ "1520" : "revision_json",
+ "sWiPMemBlock.alFree[1]" : "AdvancedMode",
+ "sWiPMemBlock.alFree[2]" : "RecoveryMode",
+ "sWiPMemBlock.alFree[3]" : "DoubleIrrMode",
+ "sWiPMemBlock.alFree[4]" : "MtMode",
+ "sWiPMemBlock.alFree[5]" : "PreparationType",
+ "sWiPMemBlock.alFree[6]" : "PulseType",
+ "sWiPMemBlock.alFree[7]" : "SamplingType",
+ "sWiPMemBlock.alFree[8]" : "SpoilingType",
+ "sWiPMemBlock.alFree[9]" : "measurements",
+ "sWiPMemBlock.alFree[10]" : "NumberRFBlocks",
+ "sWiPMemBlock.alFree[11]" : "PulsesPerRFBlock",
+ "sWiPMemBlock.alFree[12]" : "PulseDuration",
+ "sWiPMemBlock.alFree[13]" : "DutyCycle",
+ "sWiPMemBlock.alFree[14]" : "RecoveryTime",
+ "sWiPMemBlock.alFree[15]" : "RecoveryTimeM0",
+ "sWiPMemBlock.adFree[1]" : "Offset",
+ "sWiPMemBlock.adFree[2]" : "B1Amplitude",
+ "sWiPMemBlock.adFree[3]" : "AdiabaticPulseMu",
+ "sWiPMemBlock.adFree[4]" : "AdiabaticPulseBW",
+ "sWiPMemBlock.adFree[5]" : "AdiabaticPulseLength",
+ "sWiPMemBlock.adFree[6]" : "AdiabaticPulseAmp"
+}
diff --git a/Modules/CEST/resource/1521.json b/Modules/CEST/resource/1521.json
new file mode 100644
index 0000000000..dd44bdeac9
--- /dev/null
+++ b/Modules/CEST/resource/1521.json
@@ -0,0 +1,24 @@
+{
+ "1521" : "revision_json",
+ "sWiPMemBlock.alFree[1]" : "AdvancedMode",
+ "sWiPMemBlock.alFree[2]" : "RecoveryMode",
+ "sWiPMemBlock.alFree[3]" : "DoubleIrrMode",
+ "sWiPMemBlock.alFree[4]" : "MtMode",
+ "sWiPMemBlock.alFree[5]" : "PreparationType",
+ "sWiPMemBlock.alFree[6]" : "PulseType",
+ "sWiPMemBlock.alFree[7]" : "SamplingType",
+ "sWiPMemBlock.alFree[8]" : "SpoilingType",
+ "sWiPMemBlock.alFree[9]" : "measurements",
+ "sWiPMemBlock.alFree[10]" : "NumberRFBlocks",
+ "sWiPMemBlock.alFree[11]" : "PulsesPerRFBlock",
+ "sWiPMemBlock.alFree[12]" : "PulseDuration",
+ "sWiPMemBlock.alFree[13]" : "DutyCycle",
+ "sWiPMemBlock.alFree[14]" : "RecoveryTime",
+ "sWiPMemBlock.alFree[15]" : "RecoveryTimeM0",
+ "sWiPMemBlock.adFree[1]" : "Offset",
+ "sWiPMemBlock.adFree[2]" : "B1Amplitude",
+ "sWiPMemBlock.adFree[3]" : "AdiabaticPulseMu",
+ "sWiPMemBlock.adFree[4]" : "AdiabaticPulseBW",
+ "sWiPMemBlock.adFree[5]" : "AdiabaticPulseLength",
+ "sWiPMemBlock.adFree[6]" : "AdiabaticPulseAmp"
+}
diff --git a/Modules/CEST/resource/1522.json b/Modules/CEST/resource/1522.json
new file mode 100644
index 0000000000..1f298205c4
--- /dev/null
+++ b/Modules/CEST/resource/1522.json
@@ -0,0 +1,24 @@
+{
+ "1522" : "revision_json",
+ "sWiPMemBlock.alFree[1]" : "AdvancedMode",
+ "sWiPMemBlock.alFree[2]" : "RecoveryMode",
+ "sWiPMemBlock.alFree[3]" : "DoubleIrrMode",
+ "sWiPMemBlock.alFree[4]" : "MtMode",
+ "sWiPMemBlock.alFree[5]" : "PreparationType",
+ "sWiPMemBlock.alFree[6]" : "PulseType",
+ "sWiPMemBlock.alFree[7]" : "SamplingType",
+ "sWiPMemBlock.alFree[8]" : "SpoilingType",
+ "sWiPMemBlock.alFree[9]" : "measurements",
+ "sWiPMemBlock.alFree[10]" : "NumberRFBlocks",
+ "sWiPMemBlock.alFree[11]" : "PulsesPerRFBlock",
+ "sWiPMemBlock.alFree[12]" : "PulseDuration",
+ "sWiPMemBlock.alFree[13]" : "DutyCycle",
+ "sWiPMemBlock.alFree[14]" : "RecoveryTime",
+ "sWiPMemBlock.alFree[15]" : "RecoveryTimeM0",
+ "sWiPMemBlock.adFree[1]" : "Offset",
+ "sWiPMemBlock.adFree[2]" : "B1Amplitude",
+ "sWiPMemBlock.adFree[3]" : "AdiabaticPulseMu",
+ "sWiPMemBlock.adFree[4]" : "AdiabaticPulseBW",
+ "sWiPMemBlock.adFree[5]" : "AdiabaticPulseLength",
+ "sWiPMemBlock.adFree[6]" : "AdiabaticPulseAmp"
+}
diff --git a/Modules/CEST/resource/1583.json b/Modules/CEST/resource/1583.json
new file mode 100644
index 0000000000..c6ac35a621
--- /dev/null
+++ b/Modules/CEST/resource/1583.json
@@ -0,0 +1,24 @@
+{
+ "1583" : "revision_json",
+ "sWiPMemBlock.alFree[1]" : "AdvancedMode",
+ "sWiPMemBlock.alFree[2]" : "RecoveryMode",
+ "sWiPMemBlock.alFree[3]" : "DoubleIrrMode",
+ "sWiPMemBlock.alFree[4]" : "MtMode",
+ "sWiPMemBlock.alFree[5]" : "PreparationType",
+ "sWiPMemBlock.alFree[6]" : "PulseType",
+ "sWiPMemBlock.alFree[7]" : "SamplingType",
+ "sWiPMemBlock.alFree[8]" : "SpoilingType",
+ "sWiPMemBlock.alFree[9]" : "measurements",
+ "sWiPMemBlock.alFree[10]" : "NumberRFBlocks",
+ "sWiPMemBlock.alFree[11]" : "PulsesPerRFBlock",
+ "sWiPMemBlock.alFree[12]" : "PulseDuration",
+ "sWiPMemBlock.alFree[13]" : "DutyCycle",
+ "sWiPMemBlock.alFree[14]" : "RecoveryTime",
+ "sWiPMemBlock.alFree[15]" : "RecoveryTimeM0",
+ "sWiPMemBlock.adFree[1]" : "Offset",
+ "sWiPMemBlock.adFree[2]" : "B1Amplitude",
+ "sWiPMemBlock.adFree[3]" : "AdiabaticPulseMu",
+ "sWiPMemBlock.adFree[4]" : "AdiabaticPulseBW",
+ "sWiPMemBlock.adFree[5]" : "AdiabaticPulseLength",
+ "sWiPMemBlock.adFree[6]" : "AdiabaticPulseAmp"
+}
diff --git a/Modules/Core/src/Controllers/mitkRenderingManager.cpp b/Modules/Core/src/Controllers/mitkRenderingManager.cpp
index 5971ec93e7..1fe5bec198 100644
--- a/Modules/Core/src/Controllers/mitkRenderingManager.cpp
+++ b/Modules/Core/src/Controllers/mitkRenderingManager.cpp
@@ -1,778 +1,777 @@
/*============================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.
Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.
============================================================================*/
#include "mitkRenderingManager.h"
#include "mitkBaseRenderer.h"
#include "mitkCameraController.h"
#include "mitkNodePredicateNot.h"
#include "mitkNodePredicateProperty.h"
#include "mitkProportionalTimeGeometry.h"
#include "mitkRenderingManagerFactory.h"
#include
#include
#include
#include
#include "mitkNumericTypes.h"
#include
#include
#include
#include
namespace mitk
{
itkEventMacroDefinition(RenderingManagerEvent, itk::AnyEvent);
itkEventMacroDefinition(RenderingManagerViewsInitializedEvent, RenderingManagerEvent);
itkEventMacroDefinition(FocusChangedEvent, itk::AnyEvent);
RenderingManager::Pointer RenderingManager::s_Instance = nullptr;
RenderingManagerFactory *RenderingManager::s_RenderingManagerFactory = nullptr;
RenderingManager::RenderingManager()
: m_UpdatePending(false),
m_MaxLOD(1),
m_LODIncreaseBlocked(false),
m_LODAbortMechanismEnabled(false),
m_ClippingPlaneEnabled(false),
m_TimeNavigationController(SliceNavigationController::New()),
m_DataStorage(nullptr),
m_ConstrainedPanningZooming(true),
m_FocusedRenderWindow(nullptr),
m_AntiAliasing(AntiAliasing::FastApproximate)
{
m_ShadingEnabled.assign(3, false);
m_ShadingValues.assign(4, 0.0);
InitializePropertyList();
}
RenderingManager::~RenderingManager()
{
// Decrease reference counts of all registered vtkRenderWindows for
// proper destruction
RenderWindowVector::iterator it;
for (it = m_AllRenderWindows.begin(); it != m_AllRenderWindows.end(); ++it)
{
(*it)->UnRegister(nullptr);
auto callbacks_it = this->m_RenderWindowCallbacksList.find(*it);
if (callbacks_it != this->m_RenderWindowCallbacksList.end())
{
(*it)->RemoveObserver(callbacks_it->second.commands[0u]);
(*it)->RemoveObserver(callbacks_it->second.commands[1u]);
(*it)->RemoveObserver(callbacks_it->second.commands[2u]);
}
}
}
void RenderingManager::SetFactory(RenderingManagerFactory *factory) { s_RenderingManagerFactory = factory; }
const RenderingManagerFactory *RenderingManager::GetFactory() { return s_RenderingManagerFactory; }
bool RenderingManager::HasFactory()
{
if (RenderingManager::s_RenderingManagerFactory)
{
return true;
}
else
{
return false;
}
}
RenderingManager::Pointer RenderingManager::New()
{
const RenderingManagerFactory *factory = GetFactory();
if (factory == nullptr)
return nullptr;
return factory->CreateRenderingManager();
}
RenderingManager *RenderingManager::GetInstance()
{
if (!RenderingManager::s_Instance)
{
if (s_RenderingManagerFactory)
{
s_Instance = s_RenderingManagerFactory->CreateRenderingManager();
}
}
return s_Instance;
}
bool RenderingManager::IsInstantiated()
{
if (RenderingManager::s_Instance)
return true;
else
return false;
}
void RenderingManager::AddRenderWindow(vtkRenderWindow *renderWindow)
{
if (renderWindow && (m_RenderWindowList.find(renderWindow) == m_RenderWindowList.end()))
{
m_RenderWindowList[renderWindow] = RENDERING_INACTIVE;
m_AllRenderWindows.push_back(renderWindow);
if (m_DataStorage.IsNotNull())
mitk::BaseRenderer::GetInstance(renderWindow)->SetDataStorage(m_DataStorage.GetPointer());
// Register vtkRenderWindow instance
renderWindow->Register(nullptr);
// Add callbacks for rendering abort mechanism
// BaseRenderer *renderer = BaseRenderer::GetInstance( renderWindow );
vtkCallbackCommand *startCallbackCommand = vtkCallbackCommand::New();
startCallbackCommand->SetCallback(RenderingManager::RenderingStartCallback);
renderWindow->AddObserver(vtkCommand::StartEvent, startCallbackCommand);
vtkCallbackCommand *progressCallbackCommand = vtkCallbackCommand::New();
progressCallbackCommand->SetCallback(RenderingManager::RenderingProgressCallback);
renderWindow->AddObserver(vtkCommand::AbortCheckEvent, progressCallbackCommand);
vtkCallbackCommand *endCallbackCommand = vtkCallbackCommand::New();
endCallbackCommand->SetCallback(RenderingManager::RenderingEndCallback);
renderWindow->AddObserver(vtkCommand::EndEvent, endCallbackCommand);
RenderWindowCallbacks callbacks;
callbacks.commands[0u] = startCallbackCommand;
callbacks.commands[1u] = progressCallbackCommand;
callbacks.commands[2u] = endCallbackCommand;
this->m_RenderWindowCallbacksList[renderWindow] = callbacks;
// Delete vtk variables correctly
startCallbackCommand->Delete();
progressCallbackCommand->Delete();
endCallbackCommand->Delete();
}
}
void RenderingManager::RemoveRenderWindow(vtkRenderWindow *renderWindow)
{
if (m_RenderWindowList.erase(renderWindow))
{
auto callbacks_it = this->m_RenderWindowCallbacksList.find(renderWindow);
if (callbacks_it != this->m_RenderWindowCallbacksList.end())
{
renderWindow->RemoveObserver(callbacks_it->second.commands[0u]);
renderWindow->RemoveObserver(callbacks_it->second.commands[1u]);
renderWindow->RemoveObserver(callbacks_it->second.commands[2u]);
this->m_RenderWindowCallbacksList.erase(callbacks_it);
}
auto rw_it =
std::find(m_AllRenderWindows.begin(), m_AllRenderWindows.end(), renderWindow);
if (rw_it != m_AllRenderWindows.cend())
{
// Decrease reference count for proper destruction
(*rw_it)->UnRegister(nullptr);
m_AllRenderWindows.erase(rw_it);
}
}
}
const RenderingManager::RenderWindowVector &RenderingManager::GetAllRegisteredRenderWindows()
{
return m_AllRenderWindows;
}
void RenderingManager::RequestUpdate(vtkRenderWindow *renderWindow)
{
// If the renderWindow is not valid, we do not want to inadvertantly create
// an entry in the m_RenderWindowList map. It is possible if the user is
// regularly calling AddRenderer and RemoveRenderer for a rendering update
// to come into this method with a renderWindow pointer that is valid in the
// sense that the window does exist within the application, but that
// renderWindow has been temporarily removed from this RenderingManager for
// performance reasons.
if (m_RenderWindowList.find(renderWindow) == m_RenderWindowList.cend())
{
return;
}
m_RenderWindowList[renderWindow] = RENDERING_REQUESTED;
if (!m_UpdatePending)
{
m_UpdatePending = true;
this->GenerateRenderingRequestEvent();
}
}
void RenderingManager::ForceImmediateUpdate(vtkRenderWindow *renderWindow)
{
// If the renderWindow is not valid, we do not want to inadvertantly create
// an entry in the m_RenderWindowList map. It is possible if the user is
// regularly calling AddRenderer and RemoveRenderer for a rendering update
// to come into this method with a renderWindow pointer that is valid in the
// sense that the window does exist within the application, but that
// renderWindow has been temporarily removed from this RenderingManager for
// performance reasons.
if (m_RenderWindowList.find(renderWindow) == m_RenderWindowList.cend())
{
return;
}
- mitk::BaseRenderer *baseRenderer = mitk::BaseRenderer::GetInstance(renderWindow);
- baseRenderer->SetConstrainZoomingAndPanning(m_ConstrainedPanningZooming);
-
// Erase potentially pending requests for this window
m_RenderWindowList[renderWindow] = RENDERING_INACTIVE;
m_UpdatePending = false;
// Immediately repaint this window (implementation platform specific)
// If the size is 0 it crashes
int *size = renderWindow->GetSize();
if (0 != size[0] && 0 != size[1])
{
// prepare the camera etc. before rendering
// Note: this is a very important step which should be called before the VTK render!
// If you modify the camera anywhere else or after the render call, the scene cannot be seen.
- auto *vPR = dynamic_cast(baseRenderer);
+ auto *vPR = dynamic_cast(mitk::BaseRenderer::GetInstance(renderWindow));
if (vPR)
vPR->PrepareRender();
// Execute rendering
renderWindow->Render();
}
}
void RenderingManager::RequestUpdateAll(RequestType type)
{
RenderWindowList::const_iterator it;
for (it = m_RenderWindowList.cbegin(); it != m_RenderWindowList.cend(); ++it)
{
int id = BaseRenderer::GetInstance(it->first)->GetMapperID();
if ((type == REQUEST_UPDATE_ALL) || ((type == REQUEST_UPDATE_2DWINDOWS) && (id == 1)) ||
((type == REQUEST_UPDATE_3DWINDOWS) && (id == 2)))
{
this->RequestUpdate(it->first);
}
}
}
void RenderingManager::ForceImmediateUpdateAll(RequestType type)
{
RenderWindowList::const_iterator it;
for (it = m_RenderWindowList.cbegin(); it != m_RenderWindowList.cend(); ++it)
{
int id = BaseRenderer::GetInstance(it->first)->GetMapperID();
if ((type == REQUEST_UPDATE_ALL) || ((type == REQUEST_UPDATE_2DWINDOWS) && (id == 1)) ||
((type == REQUEST_UPDATE_3DWINDOWS) && (id == 2)))
{
// Immediately repaint this window (implementation platform specific)
// If the size is 0, it crashes
this->ForceImmediateUpdate(it->first);
}
}
}
void RenderingManager::InitializeViewsByBoundingObjects(const DataStorage *ds)
{
if (!ds)
return;
// get all nodes that have not set "includeInBoundingBox" to false
mitk::NodePredicateNot::Pointer pred = mitk::NodePredicateNot::New(
mitk::NodePredicateProperty::New("includeInBoundingBox", mitk::BoolProperty::New(false)));
mitk::DataStorage::SetOfObjects::ConstPointer rs = ds->GetSubset(pred);
// calculate bounding geometry of these nodes
auto bounds = ds->ComputeBoundingGeometry3D(rs, "visible");
// initialize the views to the bounding geometry
this->InitializeViews(bounds);
}
// TODO_GOETZ
// Remove old function, so only this one is working.
bool RenderingManager::InitializeViews(const BaseGeometry *dataGeometry,
RequestType type,
bool resetCamera)
{
ProportionalTimeGeometry::Pointer propTimeGeometry = ProportionalTimeGeometry::New();
propTimeGeometry->Initialize(dynamic_cast(dataGeometry->Clone().GetPointer()), 1);
return InitializeViews(propTimeGeometry, type, resetCamera);
}
bool RenderingManager::InitializeViews(const TimeGeometry *dataGeometry,
RequestType type,
bool resetCamera)
{
MITK_DEBUG << "initializing views";
bool boundingBoxInitialized = false;
TimeGeometry::ConstPointer timeGeometry = dataGeometry;
TimeGeometry::Pointer modifiedGeometry = nullptr;
if (dataGeometry != nullptr)
{
modifiedGeometry = dataGeometry->Clone();
}
int warningLevel = vtkObject::GetGlobalWarningDisplay();
vtkObject::GlobalWarningDisplayOff();
if ((timeGeometry.IsNotNull()) &&
(timeGeometry->GetBoundingBoxInWorld()->GetDiagonalLength2() > mitk::eps))
{
boundingBoxInitialized = true;
}
if (timeGeometry.IsNotNull())
{ // make sure bounding box has an extent bigger than zero in any direction
// clone the input geometry
// Old Geometry3D::Pointer modifiedGeometry = dynamic_cast( dataGeometry->Clone().GetPointer() );
assert(modifiedGeometry.IsNotNull());
for (TimeStepType step = 0; step < modifiedGeometry->CountTimeSteps(); ++step)
{
BaseGeometry::BoundsArrayType newBounds = modifiedGeometry->GetGeometryForTimeStep(step)->GetBounds();
for (unsigned int dimension = 0; (2 * dimension) < newBounds.Size(); dimension++)
{
// check for equality but for an epsilon
if (Equal(newBounds[2 * dimension], newBounds[2 * dimension + 1]))
{
newBounds[2 * dimension + 1] += 1;
if (Equal(
newBounds[2 * dimension],
newBounds[2 * dimension + 1])) // newBounds will still be equal if values are beyond double precision
{
mitkThrow() << "One dimension of object data has zero length, please make sure you're not using numbers "
"beyond double precision as coordinates.";
}
}
}
modifiedGeometry->GetGeometryForTimeStep(step)->SetBounds(newBounds);
}
}
timeGeometry = modifiedGeometry;
RenderWindowList::const_iterator it;
for (it = m_RenderWindowList.cbegin(); it != m_RenderWindowList.cend(); ++it)
{
mitk::BaseRenderer *baseRenderer = mitk::BaseRenderer::GetInstance(it->first);
+ baseRenderer->SetConstrainZoomingAndPanning(m_ConstrainedPanningZooming);
+
int id = baseRenderer->GetMapperID();
if (((type == REQUEST_UPDATE_ALL) || ((type == REQUEST_UPDATE_2DWINDOWS) && (id == 1)) ||
((type == REQUEST_UPDATE_3DWINDOWS) && (id == 2))))
{
this->InternalViewInitialization(baseRenderer, timeGeometry, boundingBoxInitialized, id, resetCamera);
}
}
if (boundingBoxInitialized)
{
m_TimeNavigationController->SetInputWorldTimeGeometry(timeGeometry);
}
m_TimeNavigationController->Update();
this->RequestUpdateAll(type);
vtkObject::SetGlobalWarningDisplay(warningLevel);
// Inform listeners that views have been initialized
this->InvokeEvent(mitk::RenderingManagerViewsInitializedEvent());
return boundingBoxInitialized;
}
bool RenderingManager::InitializeViews(RequestType type)
{
RenderWindowList::const_iterator it;
for (it = m_RenderWindowList.cbegin(); it != m_RenderWindowList.cend(); ++it)
{
mitk::BaseRenderer *baseRenderer = mitk::BaseRenderer::GetInstance(it->first);
int id = baseRenderer->GetMapperID();
if ((type == REQUEST_UPDATE_ALL) || ((type == REQUEST_UPDATE_2DWINDOWS) && (id == 1)) ||
((type == REQUEST_UPDATE_3DWINDOWS) && (id == 2)))
{
mitk::SliceNavigationController *nc =
baseRenderer->GetSliceNavigationController();
// Re-initialize view direction
nc->SetViewDirectionToDefault();
// Update the SNC
nc->Update();
}
}
this->RequestUpdateAll(type);
return true;
}
bool RenderingManager::InitializeView(vtkRenderWindow *renderWindow,
const BaseGeometry *geometry,
bool initializeGlobalTimeSNC,
bool resetCamera)
{
ProportionalTimeGeometry::Pointer propTimeGeometry = ProportionalTimeGeometry::New();
propTimeGeometry->Initialize(dynamic_cast(geometry->Clone().GetPointer()), 1);
return InitializeView(renderWindow, propTimeGeometry, initializeGlobalTimeSNC, resetCamera);
}
bool RenderingManager::InitializeView(vtkRenderWindow *renderWindow,
const TimeGeometry *geometry,
bool initializeGlobalTimeSNC,
bool resetCamera)
{
bool boundingBoxInitialized = false;
int warningLevel = vtkObject::GetGlobalWarningDisplay();
vtkObject::GlobalWarningDisplayOff();
if ((geometry != nullptr) &&
(geometry->GetBoundingBoxInWorld()->GetDiagonalLength2() > mitk::eps))
{
boundingBoxInitialized = true;
}
mitk::BaseRenderer *baseRenderer = mitk::BaseRenderer::GetInstance(renderWindow);
int id = baseRenderer->GetMapperID();
this->InternalViewInitialization(baseRenderer, geometry, boundingBoxInitialized, id, resetCamera);
if (boundingBoxInitialized && initializeGlobalTimeSNC)
{
m_TimeNavigationController->SetInputWorldTimeGeometry(geometry);
}
m_TimeNavigationController->Update();
this->RequestUpdate(renderWindow);
vtkObject::SetGlobalWarningDisplay(warningLevel);
return boundingBoxInitialized;
}
bool RenderingManager::InitializeView(vtkRenderWindow *renderWindow)
{
mitk::BaseRenderer *baseRenderer = mitk::BaseRenderer::GetInstance(renderWindow);
mitk::SliceNavigationController *nc = baseRenderer->GetSliceNavigationController();
// Re-initialize view direction
nc->SetViewDirectionToDefault();
// Update the SNC
nc->Update();
this->RequestUpdate(renderWindow);
return true;
}
void RenderingManager::InternalViewInitialization(mitk::BaseRenderer *baseRenderer,
const mitk::TimeGeometry *geometry,
bool boundingBoxInitialized,
int mapperID,
bool resetCamera)
{
mitk::SliceNavigationController *nc = baseRenderer->GetSliceNavigationController();
// Re-initialize view direction
nc->SetViewDirectionToDefault();
if (boundingBoxInitialized)
{
// Set geometry for NC
nc->SetInputWorldTimeGeometry(geometry);
nc->Update();
if (resetCamera)
{
if (mapperID == BaseRenderer::Standard2D)
{
// For 2D SNCs, steppers are set so that the cross is centered in the image
nc->GetSlice()->SetPos(nc->GetSlice()->GetSteps() / 2);
baseRenderer->GetCameraController()->Fit();
}
else if (mapperID == BaseRenderer::Standard3D)
{
baseRenderer->GetCameraController()->SetViewToAnterior();
}
}
}
else
{
nc->Update();
}
}
const SliceNavigationController *RenderingManager::GetTimeNavigationController() const
{
return m_TimeNavigationController.GetPointer();
}
SliceNavigationController *RenderingManager::GetTimeNavigationController()
{
return m_TimeNavigationController.GetPointer();
}
void RenderingManager::ExecutePendingRequests()
{
m_UpdatePending = false;
// Satisfy all pending update requests
RenderWindowList::const_iterator it;
int i = 0;
for (it = m_RenderWindowList.cbegin(); it != m_RenderWindowList.cend(); ++it, ++i)
{
if (it->second == RENDERING_REQUESTED)
{
this->ForceImmediateUpdate(it->first);
}
}
}
void RenderingManager::RenderingStartCallback(vtkObject *caller, unsigned long, void *, void *)
{
auto renderingManager = RenderingManager::GetInstance();
auto renderWindow = dynamic_cast(caller);
if (nullptr != renderWindow)
renderingManager->m_RenderWindowList[renderWindow] = RENDERING_INPROGRESS;
renderingManager->m_UpdatePending = false;
}
void RenderingManager::RenderingProgressCallback(vtkObject *caller, unsigned long, void *, void *)
{
auto renderingManager = RenderingManager::GetInstance();
if (renderingManager->m_LODAbortMechanismEnabled)
{
auto renderWindow = dynamic_cast(caller);
if (nullptr != renderWindow)
{
auto renderer = BaseRenderer::GetInstance(renderWindow);
if (nullptr != renderer && 0 < renderer->GetNumberOfVisibleLODEnabledMappers())
renderingManager->DoMonitorRendering();
}
}
}
void RenderingManager::RenderingEndCallback(vtkObject *caller, unsigned long, void *, void *)
{
auto renderWindow = dynamic_cast(caller);
if (nullptr != renderWindow)
{
auto renderer = BaseRenderer::GetInstance(renderWindow);
if (nullptr != renderer)
{
auto renderingManager = RenderingManager::GetInstance();
renderingManager->m_RenderWindowList[renderer->GetRenderWindow()] = RENDERING_INACTIVE;
if (0 < renderer->GetNumberOfVisibleLODEnabledMappers())
{
if (0 == renderingManager->m_NextLODMap[renderer])
{
renderingManager->StartOrResetTimer();
}
else
{
renderingManager->m_NextLODMap[renderer] = 0;
}
}
}
}
}
bool RenderingManager::IsRendering() const
{
RenderWindowList::const_iterator it;
for (it = m_RenderWindowList.cbegin(); it != m_RenderWindowList.cend(); ++it)
{
if (it->second == RENDERING_INPROGRESS)
{
return true;
}
}
return false;
}
void RenderingManager::AbortRendering()
{
RenderWindowList::const_iterator it;
for (it = m_RenderWindowList.cbegin(); it != m_RenderWindowList.cend(); ++it)
{
if (it->second == RENDERING_INPROGRESS)
{
it->first->SetAbortRender(true);
m_RenderingAbortedMap[BaseRenderer::GetInstance(it->first)] = true;
}
}
}
int RenderingManager::GetNextLOD(BaseRenderer *renderer)
{
if (renderer != nullptr)
{
return m_NextLODMap[renderer];
}
else
{
return 0;
}
}
void RenderingManager::ExecutePendingHighResRenderingRequest()
{
RenderWindowList::const_iterator it;
for (it = m_RenderWindowList.cbegin(); it != m_RenderWindowList.cend(); ++it)
{
BaseRenderer *renderer = BaseRenderer::GetInstance(it->first);
if (renderer->GetNumberOfVisibleLODEnabledMappers() > 0)
{
if (m_NextLODMap[renderer] == 0)
{
m_NextLODMap[renderer] = 1;
RequestUpdate(it->first);
}
}
}
}
void RenderingManager::SetMaximumLOD(unsigned int max) { m_MaxLOD = max; }
// enable/disable shading
void RenderingManager::SetShading(bool state, unsigned int lod)
{
if (lod > m_MaxLOD)
{
itkWarningMacro(<< "LOD out of range requested: " << lod << " maxLOD: " << m_MaxLOD);
return;
}
m_ShadingEnabled[lod] = state;
}
bool RenderingManager::GetShading(unsigned int lod)
{
if (lod > m_MaxLOD)
{
itkWarningMacro(<< "LOD out of range requested: " << lod << " maxLOD: " << m_MaxLOD);
return false;
}
return m_ShadingEnabled[lod];
}
// enable/disable the clipping plane
void RenderingManager::SetClippingPlaneStatus(bool status) { m_ClippingPlaneEnabled = status; }
bool RenderingManager::GetClippingPlaneStatus() { return m_ClippingPlaneEnabled; }
void RenderingManager::SetShadingValues(float ambient, float diffuse, float specular, float specpower)
{
m_ShadingValues[0] = ambient;
m_ShadingValues[1] = diffuse;
m_ShadingValues[2] = specular;
m_ShadingValues[3] = specpower;
}
RenderingManager::FloatVector &RenderingManager::GetShadingValues() { return m_ShadingValues; }
void RenderingManager::InitializePropertyList()
{
if (m_PropertyList.IsNull())
{
m_PropertyList = PropertyList::New();
}
this->SetProperty("coupled-zoom", BoolProperty::New(false));
this->SetProperty("coupled-plane-rotation", BoolProperty::New(false));
this->SetProperty("MIP-slice-rendering", BoolProperty::New(false));
}
PropertyList::Pointer RenderingManager::GetPropertyList() const { return m_PropertyList; }
BaseProperty *RenderingManager::GetProperty(const char *propertyKey) const
{
return m_PropertyList->GetProperty(propertyKey);
}
void RenderingManager::SetProperty(const char *propertyKey, BaseProperty *propertyValue)
{
m_PropertyList->SetProperty(propertyKey, propertyValue);
}
void RenderingManager::SetDataStorage(DataStorage *storage)
{
if (storage != nullptr)
{
m_DataStorage = storage;
RenderingManager::RenderWindowVector::const_iterator iter;
for (iter = m_AllRenderWindows.cbegin(); iter < m_AllRenderWindows.cend(); ++iter)
{
mitk::BaseRenderer::GetInstance((*iter))->SetDataStorage(m_DataStorage.GetPointer());
}
}
}
mitk::DataStorage *RenderingManager::GetDataStorage() { return m_DataStorage; }
void RenderingManager::SetRenderWindowFocus(vtkRenderWindow *focusWindow)
{
if (focusWindow != m_FocusedRenderWindow)
{
if (!focusWindow || (m_RenderWindowList.find(focusWindow) != m_RenderWindowList.cend()))
{
m_FocusedRenderWindow = focusWindow;
this->InvokeEvent(FocusChangedEvent());
return;
}
MITK_ERROR << "Tried to set a RenderWindow that does not exist.";
}
}
void RenderingManager::SetAntiAliasing(AntiAliasing antiAliasing)
{
if (m_AntiAliasing != antiAliasing)
{
auto renderingManager = mitk::RenderingManager::GetInstance();
auto renderWindows = renderingManager->GetAllRegisteredRenderWindows();
for (auto renderWindow : renderWindows)
{
auto renderers = renderWindow->GetRenderers();
if (nullptr != renderers)
{
renderers->InitTraversal();
auto renderer = renderers->GetNextItem();
while (nullptr != renderer)
{
renderer->SetUseFXAA(AntiAliasing::FastApproximate == antiAliasing);
renderer = renderers->GetNextItem();
}
renderingManager->RequestUpdate(renderWindow);
}
}
m_AntiAliasing = antiAliasing;
}
}
// Create and register generic RenderingManagerFactory.
TestingRenderingManagerFactory renderingManagerFactory;
} // namespace
diff --git a/Modules/CoreCmdApps/FileConverter.cpp b/Modules/CoreCmdApps/FileConverter.cpp
index 009c67c1e1..197fa9fa67 100644
--- a/Modules/CoreCmdApps/FileConverter.cpp
+++ b/Modules/CoreCmdApps/FileConverter.cpp
@@ -1,112 +1,116 @@
/*============================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.
Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.
============================================================================*/
#include "mitkProperties.h"
#include "mitkCommandLineParser.h"
#include "mitkIOUtil.h"
#include
#include "mitkPreferenceListReaderOptionsFunctor.h"
int main(int argc, char* argv[])
{
mitkCommandLineParser parser;
parser.setTitle("File Converter");
parser.setCategory("Basic Image Processing");
parser.setDescription("");
parser.setContributor("German Cancer Research Center (DKFZ)");
parser.setArgumentPrefix("--","-");
// Add command line argument names
parser.addArgument("help", "h",mitkCommandLineParser::Bool, "Help:", "Show this help text");
parser.addArgument("input", "i", mitkCommandLineParser::File, "Input file:", "Input File",us::Any(),false, false, false, mitkCommandLineParser::Input);
parser.addArgument("output", "o", mitkCommandLineParser::File, "Output file:", "Output file", us::Any(), false, false, false, mitkCommandLineParser::Output);
parser.addArgument("reader", "r", mitkCommandLineParser::String, "Reader Name", "Reader Name", us::Any());
parser.addArgument("list-readers", "lr", mitkCommandLineParser::Bool, "Reader Name", "Reader Name", us::Any());
std::map parsedArgs = parser.parseArguments(argc, argv);
if (parsedArgs.size()==0)
return EXIT_FAILURE;
// Show a help message
if ( parsedArgs.count("help") || parsedArgs.count("h"))
{
std::cout << parser.helpText();
return EXIT_SUCCESS;
}
std::string inputFilename = us::any_cast(parsedArgs["input"]);
std::string outputFilename = us::any_cast(parsedArgs["output"]);
mitk::PreferenceListReaderOptionsFunctor::ListType preference = {};
if (parsedArgs.count("reader"))
{
preference.push_back(us::any_cast(parsedArgs["reader"]));
}
if (parsedArgs.count("list-readers"))
{
mitk::IOUtil::LoadInfo loadInfo(inputFilename);
auto readers = loadInfo.m_ReaderSelector.Get();
std::string errMsg;
if (readers.empty())
{
if (!itksys::SystemTools::FileExists(loadInfo.m_Path.c_str()))
{
errMsg += "File '" + loadInfo.m_Path + "' does not exist\n";
}
else
{
errMsg += "No reader available for '" + loadInfo.m_Path + "'\n";
}
MITK_ERROR << errMsg;
return 0;
}
std::cout << "Available Readers: "< 0)
{
- writeName = path + "/" + filename + "_" + std::to_string(count) + extension;
+ writeName = path + filename + "_" + std::to_string(count) + extension;
}
mitk::IOUtil::Save(node, writeName);
++count;
}
return EXIT_SUCCESS;
}
diff --git a/Modules/MapperExt/src/mitkVolumeMapperVtkSmart3D.cpp b/Modules/MapperExt/src/mitkVolumeMapperVtkSmart3D.cpp
index ee9a32ef57..03cd67e759 100644
--- a/Modules/MapperExt/src/mitkVolumeMapperVtkSmart3D.cpp
+++ b/Modules/MapperExt/src/mitkVolumeMapperVtkSmart3D.cpp
@@ -1,237 +1,236 @@
/*============================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.
Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.
============================================================================*/
#include "mitkVolumeMapperVtkSmart3D.h"
#include "mitkTransferFunctionProperty.h"
#include "mitkTransferFunctionInitializer.h"
#include "mitkLevelWindowProperty.h"
#include
#include
#include
#include
void mitk::VolumeMapperVtkSmart3D::GenerateDataForRenderer(mitk::BaseRenderer *renderer)
{
bool value;
this->GetDataNode()->GetBoolProperty("volumerendering", value, renderer);
if (!value)
{
m_Volume->VisibilityOff();
return;
}
else
{
+ createMapper(GetInputImage());
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("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 = 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->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()
{
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/Multilabel/mitkLabelSet.cpp b/Modules/Multilabel/mitkLabelSet.cpp
index 3452a9a90b..47f5472fdf 100644
--- a/Modules/Multilabel/mitkLabelSet.cpp
+++ b/Modules/Multilabel/mitkLabelSet.cpp
@@ -1,363 +1,360 @@
/*============================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.
Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.
============================================================================*/
#include "mitkLabelSet.h"
#include "mitkDICOMSegmentationPropertyHelper.h"
#include
mitk::LabelSet::LabelSet() : m_ActiveLabelValue(0), m_Layer(0)
{
m_LookupTable = mitk::LookupTable::New();
m_LookupTable->SetType(mitk::LookupTable::MULTILABEL);
}
mitk::LabelSet::~LabelSet()
{
m_LabelContainer.clear();
}
mitk::LabelSet::LabelSet(const LabelSet &other)
: itk::Object(),
m_LookupTable(other.GetLookupTable()->Clone()),
m_ActiveLabelValue(other.GetActiveLabel()->GetValue()),
m_Layer(other.GetLayer())
{
// clone Labels
auto otherIt = other.IteratorConstBegin();
for (; otherIt != other.IteratorConstEnd(); ++otherIt)
{
m_LabelContainer[otherIt->first] = otherIt->second->Clone();
itk::SimpleMemberCommand::Pointer command = itk::SimpleMemberCommand::New();
command->SetCallbackFunction(this, &LabelSet::OnLabelModified);
m_LabelContainer[otherIt->first]->AddObserver(itk::ModifiedEvent(), command);
}
}
void mitk::LabelSet::OnLabelModified()
{
ModifyLabelEvent.Send();
Superclass::Modified();
}
mitk::LabelSet::LabelContainerConstIteratorType mitk::LabelSet::IteratorConstEnd() const
{
return m_LabelContainer.end();
}
mitk::LabelSet::LabelContainerConstIteratorType mitk::LabelSet::IteratorConstBegin() const
{
return m_LabelContainer.begin();
}
mitk::LabelSet::LabelContainerIteratorType mitk::LabelSet::IteratorEnd()
{
return m_LabelContainer.end();
}
mitk::LabelSet::LabelContainerIteratorType mitk::LabelSet::IteratorBegin()
{
return m_LabelContainer.begin();
}
unsigned int mitk::LabelSet::GetNumberOfLabels() const
{
return m_LabelContainer.size();
}
void mitk::LabelSet::SetLayer(unsigned int layer)
{
m_Layer = layer;
Modified();
}
void mitk::LabelSet::SetActiveLabel(PixelType pixelValue)
{
m_ActiveLabelValue = pixelValue;
ActiveLabelEvent.Send(pixelValue);
Modified();
}
bool mitk::LabelSet::ExistLabel(PixelType pixelValue)
{
return m_LabelContainer.count(pixelValue) > 0 ? true : false;
}
// TODO Parameter as Smartpointer
void mitk::LabelSet::AddLabel(mitk::Label *label)
{
unsigned int max_size = mitk::Label::MAX_LABEL_VALUE + 1;
if (m_LabelContainer.size() >= max_size)
return;
mitk::Label::Pointer newLabel(label->Clone());
// TODO use layer of label parameter
newLabel->SetLayer(m_Layer);
PixelType pixelValue;
if (m_LabelContainer.empty())
{
pixelValue = newLabel->GetValue();
}
else
{
pixelValue = m_LabelContainer.rbegin()->first;
if (pixelValue >= newLabel->GetValue() && m_LabelContainer.find(newLabel->GetValue()) != m_LabelContainer.end())
{
++pixelValue;
newLabel->SetValue(pixelValue);
}
else
{
pixelValue = newLabel->GetValue();
}
}
// new map entry
m_LabelContainer[pixelValue] = newLabel;
UpdateLookupTable(pixelValue);
// add DICOM information of the label
DICOMSegmentationPropertyHelper::SetDICOMSegmentProperties(newLabel);
itk::SimpleMemberCommand::Pointer command = itk::SimpleMemberCommand::New();
command->SetCallbackFunction(this, &LabelSet::OnLabelModified);
newLabel->AddObserver(itk::ModifiedEvent(), command);
// newLabel->AddObserver(itk::ModifiedEvent(),command);
SetActiveLabel(newLabel->GetValue());
AddLabelEvent.Send();
Modified();
}
void mitk::LabelSet::AddLabel(const std::string &name, const mitk::Color &color)
{
- if (m_LabelContainer.size() > 255)
- return;
-
mitk::Label::Pointer newLabel = mitk::Label::New();
newLabel->SetName(name);
newLabel->SetColor(color);
AddLabel(newLabel);
}
void mitk::LabelSet::RenameLabel(PixelType pixelValue, const std::string &name, const mitk::Color &color)
{
mitk::Label *label = GetLabel(pixelValue);
label->SetName(name);
label->SetColor(color);
// change DICOM information of the label
DICOMSegmentationPropertyHelper::SetDICOMSegmentProperties(label);
}
void mitk::LabelSet::SetLookupTable(mitk::LookupTable *lut)
{
m_LookupTable = lut;
Modified();
}
void mitk::LabelSet::PrintSelf(std::ostream & /*os*/, itk::Indent /*indent*/) const
{
}
void mitk::LabelSet::RemoveLabel(PixelType pixelValue)
{
auto it = m_LabelContainer.rbegin();
PixelType nextActivePixelValue = it->first;
for (; it != m_LabelContainer.rend(); ++it)
{
if (it->first == pixelValue)
{
it->second->RemoveAllObservers();
m_LabelContainer.erase(pixelValue);
break;
}
nextActivePixelValue = it->first;
}
if (m_ActiveLabelValue == pixelValue)
{
if (ExistLabel(nextActivePixelValue))
SetActiveLabel(nextActivePixelValue);
else
SetActiveLabel(m_LabelContainer.rbegin()->first);
}
RemoveLabelEvent.Send();
Modified();
}
void mitk::LabelSet::RemoveAllLabels()
{
auto _it = IteratorBegin();
for (; _it != IteratorConstEnd();)
{
RemoveLabelEvent.Send();
m_LabelContainer.erase(_it++);
}
AllLabelsModifiedEvent.Send();
}
void mitk::LabelSet::SetNextActiveLabel()
{
auto it = m_LabelContainer.begin();
for (; it != m_LabelContainer.end(); ++it)
{
if (it->first == m_ActiveLabelValue)
{
// go to next label
++it;
if (it == m_LabelContainer.end())
{
// end of container; next label is first label
it = m_LabelContainer.begin();
}
break; // found the active label; finish loop
}
}
SetActiveLabel(it->first);
}
void mitk::LabelSet::SetAllLabelsLocked(bool value)
{
auto _end = m_LabelContainer.end();
auto _it = m_LabelContainer.begin();
for (; _it != _end; ++_it)
_it->second->SetLocked(value);
AllLabelsModifiedEvent.Send();
Modified();
}
void mitk::LabelSet::SetAllLabelsVisible(bool value)
{
auto _end = m_LabelContainer.end();
auto _it = m_LabelContainer.begin();
for (; _it != _end; ++_it)
{
_it->second->SetVisible(value);
UpdateLookupTable(_it->first);
}
AllLabelsModifiedEvent.Send();
Modified();
}
void mitk::LabelSet::UpdateLookupTable(PixelType pixelValue)
{
const mitk::Color &color = GetLabel(pixelValue)->GetColor();
double rgba[4];
m_LookupTable->GetTableValue(static_cast(pixelValue), rgba);
rgba[0] = color.GetRed();
rgba[1] = color.GetGreen();
rgba[2] = color.GetBlue();
if (GetLabel(pixelValue)->GetVisible())
rgba[3] = GetLabel(pixelValue)->GetOpacity();
else
rgba[3] = 0.0;
m_LookupTable->SetTableValue(static_cast(pixelValue), rgba);
}
mitk::Label *mitk::LabelSet::GetLabel(PixelType pixelValue)
{
if (m_LabelContainer.find(pixelValue) == m_LabelContainer.end())
return nullptr;
return m_LabelContainer[pixelValue];
}
const mitk::Label *mitk::LabelSet::GetLabel(PixelType pixelValue) const
{
auto it = m_LabelContainer.find(pixelValue);
if (it == m_LabelContainer.end())
return nullptr;
return it->second.GetPointer();
}
bool mitk::Equal(const mitk::LabelSet &leftHandSide, const mitk::LabelSet &rightHandSide, ScalarType eps, bool verbose)
{
bool returnValue = true;
// LabelSetmembers
MITK_INFO(verbose) << "--- LabelSet Equal ---";
// m_LookupTable;
const mitk::LookupTable *lhsLUT = leftHandSide.GetLookupTable();
const mitk::LookupTable *rhsLUT = rightHandSide.GetLookupTable();
returnValue = *lhsLUT == *rhsLUT;
if (!returnValue)
{
MITK_INFO(verbose) << "Lookup tabels not equal.";
return returnValue;
;
}
// m_ActiveLabel;
returnValue = mitk::Equal(*leftHandSide.GetActiveLabel(), *rightHandSide.GetActiveLabel(), eps, verbose);
if (!returnValue)
{
MITK_INFO(verbose) << "Active label not equal.";
return returnValue;
;
}
// m_Layer;
returnValue = leftHandSide.GetLayer() == rightHandSide.GetLayer();
if (!returnValue)
{
MITK_INFO(verbose) << "Layer index not equal.";
return returnValue;
;
}
// container size;
returnValue = leftHandSide.GetNumberOfLabels() == rightHandSide.GetNumberOfLabels();
if (!returnValue)
{
MITK_INFO(verbose) << "Number of labels not equal.";
return returnValue;
;
}
// Label container (map)
// m_LabelContainer;
auto lhsit = leftHandSide.IteratorConstBegin();
auto rhsit = rightHandSide.IteratorConstBegin();
for (; lhsit != leftHandSide.IteratorConstEnd(); ++lhsit, ++rhsit)
{
returnValue = rhsit->first == lhsit->first;
if (!returnValue)
{
MITK_INFO(verbose) << "Label in label container not equal.";
return returnValue;
;
}
returnValue = mitk::Equal(*(rhsit->second), *(lhsit->second), eps, verbose);
if (!returnValue)
{
MITK_INFO(verbose) << "Label in label container not equal.";
return returnValue;
;
}
}
return returnValue;
}
diff --git a/Modules/Pharmacokinetics/src/Models/mitkExtendedToftsModel.cpp b/Modules/Pharmacokinetics/src/Models/mitkExtendedToftsModel.cpp
index 4c53a5c238..dedc6d3917 100644
--- a/Modules/Pharmacokinetics/src/Models/mitkExtendedToftsModel.cpp
+++ b/Modules/Pharmacokinetics/src/Models/mitkExtendedToftsModel.cpp
@@ -1,177 +1,182 @@
/*============================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.
Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.
============================================================================*/
#include "mitkExtendedToftsModel.h"
#include "mitkConvolutionHelper.h"
#include
#include
const std::string mitk::ExtendedToftsModel::MODEL_DISPLAY_NAME = "Extended Tofts Model";
const std::string mitk::ExtendedToftsModel::NAME_PARAMETER_Ktrans = "KTrans";
const std::string mitk::ExtendedToftsModel::NAME_PARAMETER_ve = "ve";
const std::string mitk::ExtendedToftsModel::NAME_PARAMETER_vp = "vp";
const std::string mitk::ExtendedToftsModel::UNIT_PARAMETER_Ktrans = "ml/min/100ml";
const std::string mitk::ExtendedToftsModel::UNIT_PARAMETER_ve = "ml/ml";
const std::string mitk::ExtendedToftsModel::UNIT_PARAMETER_vp = "ml/ml";
const unsigned int mitk::ExtendedToftsModel::POSITION_PARAMETER_Ktrans = 0;
const unsigned int mitk::ExtendedToftsModel::POSITION_PARAMETER_ve = 1;
const unsigned int mitk::ExtendedToftsModel::POSITION_PARAMETER_vp = 2;
const unsigned int mitk::ExtendedToftsModel::NUMBER_OF_PARAMETERS = 3;
std::string mitk::ExtendedToftsModel::GetModelDisplayName() const
{
return MODEL_DISPLAY_NAME;
};
std::string mitk::ExtendedToftsModel::GetModelType() const
{
return "Perfusion.MR";
};
mitk::ExtendedToftsModel::ExtendedToftsModel()
{
}
mitk::ExtendedToftsModel::~ExtendedToftsModel()
{
}
mitk::ExtendedToftsModel::ParameterNamesType mitk::ExtendedToftsModel::GetParameterNames() const
{
ParameterNamesType result;
result.push_back(NAME_PARAMETER_Ktrans);
result.push_back(NAME_PARAMETER_ve);
result.push_back(NAME_PARAMETER_vp);
return result;
}
mitk::ExtendedToftsModel::ParametersSizeType mitk::ExtendedToftsModel::GetNumberOfParameters()
const
{
return NUMBER_OF_PARAMETERS;
}
mitk::ExtendedToftsModel::ParamterUnitMapType
mitk::ExtendedToftsModel::GetParameterUnits() const
{
ParamterUnitMapType result;
result.insert(std::make_pair(NAME_PARAMETER_Ktrans, UNIT_PARAMETER_Ktrans));
result.insert(std::make_pair(NAME_PARAMETER_vp, UNIT_PARAMETER_vp));
result.insert(std::make_pair(NAME_PARAMETER_ve, UNIT_PARAMETER_ve));
return result;
};
mitk::ExtendedToftsModel::ParameterNamesType
mitk::ExtendedToftsModel::GetDerivedParameterNames() const
{
ParameterNamesType result;
result.push_back("kep");
return result;
};
mitk::ExtendedToftsModel::ParametersSizeType
mitk::ExtendedToftsModel::GetNumberOfDerivedParameters() const
{
return 1;
};
mitk::ExtendedToftsModel::ParamterUnitMapType mitk::ExtendedToftsModel::GetDerivedParameterUnits() const
{
ParamterUnitMapType result;
result.insert(std::make_pair("kep", "1/min"));
return result;
};
mitk::ExtendedToftsModel::ModelResultType mitk::ExtendedToftsModel::ComputeModelfunction(
const ParametersType& parameters) const
{
if (this->m_TimeGrid.GetSize() == 0)
{
itkExceptionMacro("No Time Grid Set! Cannot Calculate Signal");
}
AterialInputFunctionType aterialInputFunction;
aterialInputFunction = GetAterialInputFunction(this->m_TimeGrid);
unsigned int timeSteps = this->m_TimeGrid.GetSize();
//Model Parameters
double ktrans = parameters[POSITION_PARAMETER_Ktrans] / 6000.0;
double ve = parameters[POSITION_PARAMETER_ve];
double vp = parameters[POSITION_PARAMETER_vp];
+ if (ve == 0.0)
+ {
+ itkExceptionMacro("ve is 0! Cannot calculate signal");
+ }
+
double lambda = ktrans / ve;
mitk::ModelBase::ModelResultType convolution = mitk::convoluteAIFWithExponential(this->m_TimeGrid,
aterialInputFunction, lambda);
//Signal that will be returned by ComputeModelFunction
mitk::ModelBase::ModelResultType signal(timeSteps);
signal.fill(0.0);
mitk::ModelBase::ModelResultType::iterator signalPos = signal.begin();
mitk::ModelBase::ModelResultType::const_iterator res = convolution.begin();
for (AterialInputFunctionType::iterator Cp = aterialInputFunction.begin();
Cp != aterialInputFunction.end(); ++res, ++signalPos, ++Cp)
{
*signalPos = (*Cp) * vp + ktrans * (*res);
}
return signal;
}
mitk::ModelBase::DerivedParameterMapType mitk::ExtendedToftsModel::ComputeDerivedParameters(
const mitk::ModelBase::ParametersType& parameters) const
{
DerivedParameterMapType result;
double kep = parameters[POSITION_PARAMETER_Ktrans] / parameters[POSITION_PARAMETER_ve];
result.insert(std::make_pair("kep", kep));
return result;
};
itk::LightObject::Pointer mitk::ExtendedToftsModel::InternalClone() const
{
ExtendedToftsModel::Pointer newClone = ExtendedToftsModel::New();
newClone->SetTimeGrid(this->m_TimeGrid);
return newClone.GetPointer();
};
void mitk::ExtendedToftsModel::PrintSelf(std::ostream& os, ::itk::Indent indent) const
{
Superclass::PrintSelf(os, indent);
};
diff --git a/Modules/Pharmacokinetics/test/files.cmake b/Modules/Pharmacokinetics/test/files.cmake
index 713e14913f..d6ce07a366 100644
--- a/Modules/Pharmacokinetics/test/files.cmake
+++ b/Modules/Pharmacokinetics/test/files.cmake
@@ -1,4 +1,7 @@
SET(MODULE_TESTS
mitkDescriptivePharmacokineticBrixModelTest.cpp
+ mitkStandardToftsModelTest.cpp
#ConvertToConcentrationTest.cpp
+ mitkTwoCompartmentExchangeModelTest.cpp
+ mitkExtendedToftsModelTest.cpp
)
diff --git a/Modules/Pharmacokinetics/test/mitkExtendedToftsModelTest.cpp b/Modules/Pharmacokinetics/test/mitkExtendedToftsModelTest.cpp
new file mode 100644
index 0000000000..5bd2a350e1
--- /dev/null
+++ b/Modules/Pharmacokinetics/test/mitkExtendedToftsModelTest.cpp
@@ -0,0 +1,164 @@
+/*============================================================================
+
+The Medical Imaging Interaction Toolkit (MITK)
+
+Copyright (c) German Cancer Research Center (DKFZ)
+All rights reserved.
+
+Use of this source code is governed by a 3-clause BSD license that can be
+found in the LICENSE file.
+
+============================================================================*/
+
+// Testing
+#include "mitkTestingMacros.h"
+#include "mitkTestFixture.h"
+#include "math.h"
+
+//MITK includes
+#include "mitkVector.h"
+#include "mitkExtendedToftsModel.h"
+#include "mitkAIFBasedModelBase.h"
+
+class mitkExtendedToftsModelTestSuite : public mitk::TestFixture
+{
+ CPPUNIT_TEST_SUITE(mitkExtendedToftsModelTestSuite);
+ MITK_TEST(GetModelDisplayNameTest);
+ MITK_TEST(GetModelTypeTest);
+ MITK_TEST(GetParameterNamesTest);
+ MITK_TEST(GetNumberOfParametersTest);
+ MITK_TEST(GetParameterUnitsTest);
+ MITK_TEST(GetDerivedParameterNamesTest);
+ MITK_TEST(GetNumberOfDerivedParametersTest);
+ MITK_TEST(GetDerivedParameterUnitsTest);
+ MITK_TEST(ComputeModelfunctionTest);
+ MITK_TEST(ComputeDerivedParametersTest);
+ CPPUNIT_TEST_SUITE_END();
+
+private:
+ mitk::ExtendedToftsModel::Pointer m_testmodel;
+ mitk::ModelBase::ModelResultType m_output;
+ mitk::ModelBase::DerivedParameterMapType m_derivedParameters;
+
+public:
+ void setUp() override
+ {
+ mitk::ModelBase::TimeGridType m_grid(60);
+ mitk::ModelBase::ParametersType m_testparameters(3);
+ mitk::AIFBasedModelBase::AterialInputFunctionType m_arterialInputFunction (60);
+
+ m_testparameters[mitk::ExtendedToftsModel::POSITION_PARAMETER_Ktrans] = 35.0;
+ m_testparameters(mitk::ExtendedToftsModel::POSITION_PARAMETER_ve) = 0.5;
+ m_testparameters[mitk::ExtendedToftsModel::POSITION_PARAMETER_vp] = 0.05;
+
+ for (int i = 0; i < 22; ++i)
+ {
+ // time grid in seconds, 14s between frames
+ m_grid[i] = (double)14 * i;
+ }
+
+ // AIF from Weinmann, H. J., Laniado, M., and W.Mützel (1984). Pharmacokinetics of GD - DTPA / dimeglumine after intravenous injection into healthy volunteers. Phys Chem Phys Med NMR, 16(2) : 167–72.
+ int D = 1;
+ double a1 = 3.99;
+ double m1 = 0.144;
+ double a2 = 4.78;
+ double m2 = 0.0111;
+ for (int i = 0; i < 22; ++i)
+ {
+ m_arterialInputFunction[i] = D * (a1 * exp(-m1 * m_grid[i]) + a2 * exp(-m2 * m_grid[i]));
+ }
+
+ m_testmodel = mitk::ExtendedToftsModel::New();
+ m_testmodel->SetTimeGrid(m_grid);
+ m_testmodel->SetAterialInputFunctionValues(m_arterialInputFunction);
+ m_testmodel->SetAterialInputFunctionTimeGrid(m_grid);
+
+ //ComputeModelfunction is called within GetSignal(), therefore no explicit testing of ComputeModelFunction()
+ m_output = m_testmodel->GetSignal(m_testparameters);
+ m_derivedParameters = m_testmodel->GetDerivedParameters(m_testparameters);
+ }
+
+ void tearDown() override
+ {
+ m_testmodel = nullptr;
+ m_output.clear();
+ m_derivedParameters.clear();
+ }
+
+ void GetModelDisplayNameTest()
+ {
+ m_testmodel->GetModelDisplayName();
+ CPPUNIT_ASSERT_MESSAGE("Checking model display name.", m_testmodel->GetModelDisplayName() == "Extended Tofts Model");
+ }
+
+
+ void GetModelTypeTest()
+ {
+ CPPUNIT_ASSERT_MESSAGE("Checking model type.", m_testmodel->GetModelType() == "Perfusion.MR");
+ }
+
+
+ void GetParameterNamesTest()
+ {
+ mitk::ExtendedToftsModel::ParameterNamesType parameterNames;
+ parameterNames.push_back("KTrans");
+ parameterNames.push_back("ve");
+ parameterNames.push_back("vp");
+ CPPUNIT_ASSERT_MESSAGE("Checking parameter names.", m_testmodel->GetParameterNames() == parameterNames);
+ }
+
+ void GetNumberOfParametersTest()
+ {
+ CPPUNIT_ASSERT_MESSAGE("Checking number of parameters in model.", m_testmodel->GetNumberOfParameters() == 3);
+ }
+
+
+ void GetParameterUnitsTest()
+ {
+ mitk::ExtendedToftsModel::ParamterUnitMapType parameterUnits;
+ parameterUnits.insert(std::make_pair("KTrans", "ml/min/100ml"));
+ parameterUnits.insert(std::make_pair("vp", "ml/ml"));
+ parameterUnits.insert(std::make_pair("ve","ml/ml"));
+
+ CPPUNIT_ASSERT_MESSAGE("Checking parameter units.", m_testmodel->GetParameterUnits() == parameterUnits);
+ }
+
+ void GetDerivedParameterNamesTest()
+ {
+ mitk::ExtendedToftsModel::ParameterNamesType derivedParameterNames;
+
+ derivedParameterNames.push_back("kep");
+
+ CPPUNIT_ASSERT_MESSAGE("Checking derived parameter names.", m_testmodel->GetDerivedParameterNames() == derivedParameterNames);
+ }
+
+ void GetNumberOfDerivedParametersTest()
+ {
+ CPPUNIT_ASSERT_MESSAGE("Checking number of parameters in model.", m_testmodel->GetNumberOfDerivedParameters() == 1);
+ }
+
+ void GetDerivedParameterUnitsTest()
+ {
+ mitk::ExtendedToftsModel::ParamterUnitMapType derivedParameterUnits;
+ derivedParameterUnits.insert(std::make_pair("kep", "1/min"));
+
+ CPPUNIT_ASSERT_MESSAGE("Checking parameter units.", m_testmodel->GetDerivedParameterUnits() == derivedParameterUnits);
+ }
+
+ void ComputeModelfunctionTest()
+ {
+ CPPUNIT_ASSERT_MESSAGE("Checking signal at time frame 0.", mitk::Equal(0.438500, m_output[0], 1e-6, true) == true);
+ CPPUNIT_ASSERT_MESSAGE("Checking signal at time frame 5.", mitk::Equal(1.094436, m_output[5], 1e-6, true) == true);
+ CPPUNIT_ASSERT_MESSAGE("Checking signal at time frame 10", mitk::Equal(0.890956, m_output[10], 1e-6, true) == true);
+ CPPUNIT_ASSERT_MESSAGE("Checking signal at time frame 15", mitk::Equal(0.580996, m_output[15], 1e-6, true) == true);
+ CPPUNIT_ASSERT_MESSAGE("Checking signal at time frame 20", mitk::Equal(0.342851, m_output[20], 1e-6, true) == true);
+ }
+
+ void ComputeDerivedParametersTest()
+ {
+ CPPUNIT_ASSERT_MESSAGE("Checking kep.", mitk::Equal(70.00, m_derivedParameters["kep"], 1e-6, true) == true);
+ }
+
+};
+
+MITK_TEST_SUITE_REGISTRATION(mitkExtendedToftsModel)
diff --git a/Modules/Pharmacokinetics/test/mitkStandardToftsModelTest.cpp b/Modules/Pharmacokinetics/test/mitkStandardToftsModelTest.cpp
new file mode 100644
index 0000000000..5b0c907166
--- /dev/null
+++ b/Modules/Pharmacokinetics/test/mitkStandardToftsModelTest.cpp
@@ -0,0 +1,162 @@
+/*============================================================================
+
+The Medical Imaging Interaction Toolkit (MITK)
+
+Copyright (c) German Cancer Research Center (DKFZ)
+All rights reserved.
+
+Use of this source code is governed by a 3-clause BSD license that can be
+found in the LICENSE file.
+
+============================================================================*/
+
+// Testing
+#include "mitkTestingMacros.h"
+#include "mitkTestFixture.h"
+
+//MITK includes
+#include "mitkVector.h"
+#include "mitkStandardToftsModel.h"
+#include "mitkAIFBasedModelBase.h"
+
+class mitkStandardToftsModelTestSuite : public mitk::TestFixture
+{
+ CPPUNIT_TEST_SUITE(mitkStandardToftsModelTestSuite);
+ MITK_TEST(GetModelDisplayNameTest);
+ MITK_TEST(GetModelTypeTest);
+ MITK_TEST(GetParameterNamesTest);
+ MITK_TEST(GetNumberOfParametersTest);
+ MITK_TEST(GetParameterUnitsTest);
+ MITK_TEST(GetDerivedParameterNamesTest);
+ MITK_TEST(GetNumberOfDerivedParametersTest);
+ MITK_TEST(GetDerivedParameterUnitsTest);
+ MITK_TEST(ComputeModelfunctionTest);
+ MITK_TEST(ComputeDerivedParametersTest);
+ CPPUNIT_TEST_SUITE_END();
+
+private:
+ mitk::StandardToftsModel::Pointer m_testmodel;
+ mitk::ModelBase::ModelResultType m_output;
+ mitk::ModelBase::DerivedParameterMapType m_derivedParameters;
+
+public:
+ void setUp() override
+ {
+ mitk::ModelBase::TimeGridType m_grid(22);
+ mitk::ModelBase::ParametersType m_testparameters(2);
+ mitk::AIFBasedModelBase::AterialInputFunctionType m_arterialInputFunction (22);
+
+ m_testparameters[mitk::StandardToftsModel::POSITION_PARAMETER_Ktrans] = 35.0;
+ m_testparameters(mitk::StandardToftsModel::POSITION_PARAMETER_ve) = 0.5;
+
+ for (int i = 0; i < 22; ++i)
+ {
+ // time grid in seconds, 14s between frames
+ m_grid[i] = (double)14 * i;
+ }
+
+ // AIF from Weinmann, H. J., Laniado, M., and W.Mützel (1984). Pharmacokinetics of GD - DTPA / dimeglumine after intravenous injection into healthy volunteers. Phys Chem Phys Med NMR, 16(2) : 167–72.
+ int D = 1;
+ double a1 = 3.99;
+ double m1 = 0.144;
+ double a2 = 4.78;
+ double m2 = 0.0111;
+ for (int i = 0; i < 22; ++i)
+ {
+ if (i < 5)
+ m_arterialInputFunction[i] = 0;
+ else
+ m_arterialInputFunction[i] = D * (a1 * exp(-m1 * m_grid[i]) + a2 * exp(-m2 * m_grid[i]));
+ }
+
+ m_testmodel = mitk::StandardToftsModel::New();
+ m_testmodel->SetTimeGrid(m_grid);
+ m_testmodel->SetAterialInputFunctionValues(m_arterialInputFunction);
+ m_testmodel->SetAterialInputFunctionTimeGrid(m_grid);
+
+ //ComputeModelfunction is called within GetSignal(), therefore no explicit testing of ComputeModelFunction()
+ m_output = m_testmodel->GetSignal(m_testparameters);
+ m_derivedParameters = m_testmodel->GetDerivedParameters(m_testparameters);
+ }
+
+ void tearDown() override
+ {
+ m_testmodel = nullptr;
+ m_output.clear();
+ m_derivedParameters.clear();
+ }
+
+ void GetModelDisplayNameTest()
+ {
+ m_testmodel->GetModelDisplayName();
+ CPPUNIT_ASSERT_MESSAGE("Checking model display name.", m_testmodel->GetModelDisplayName() == "Standard Tofts Model");
+ }
+
+
+ void GetModelTypeTest()
+ {
+ CPPUNIT_ASSERT_MESSAGE("Checking model type.", m_testmodel->GetModelType() == "Perfusion.MR");
+ }
+
+
+ void GetParameterNamesTest()
+ {
+ mitk::StandardToftsModel::ParameterNamesType parameterNames;
+ parameterNames.push_back("KTrans");
+ parameterNames.push_back("ve");
+ CPPUNIT_ASSERT_MESSAGE("Checking parameter names.", m_testmodel->GetParameterNames() == parameterNames);
+ }
+
+ void GetNumberOfParametersTest()
+ {
+ CPPUNIT_ASSERT_MESSAGE("Checking number of parameters in model.", m_testmodel->GetNumberOfParameters() == 2);
+ }
+
+
+ void GetParameterUnitsTest()
+ {
+ mitk::StandardToftsModel::ParamterUnitMapType parameterUnits;
+ parameterUnits.insert(std::make_pair("KTrans", "ml/min/100ml"));
+ parameterUnits.insert(std::make_pair("ve", "ml/ml"));
+
+ CPPUNIT_ASSERT_MESSAGE("Checking parameter units.", m_testmodel->GetParameterUnits() == parameterUnits);
+ }
+
+ void GetDerivedParameterNamesTest()
+ {
+ mitk::StandardToftsModel::ParameterNamesType derivedParameterNames;
+
+ derivedParameterNames.push_back("kep");
+
+ CPPUNIT_ASSERT_MESSAGE("Checking derived parameter names.", m_testmodel->GetDerivedParameterNames() == derivedParameterNames);
+ }
+
+ void GetNumberOfDerivedParametersTest()
+ {
+ CPPUNIT_ASSERT_MESSAGE("Checking number of parameters in model.", m_testmodel->GetNumberOfDerivedParameters() == 1);
+ }
+
+ void GetDerivedParameterUnitsTest()
+ {
+ mitk::StandardToftsModel::ParamterUnitMapType derivedParameterUnits;
+ derivedParameterUnits.insert(std::make_pair("kep", "1/min"));
+
+ CPPUNIT_ASSERT_MESSAGE("Checking parameter units.", m_testmodel->GetDerivedParameterUnits() == derivedParameterUnits);
+ }
+
+ void ComputeModelfunctionTest()
+ {
+ CPPUNIT_ASSERT_MESSAGE("Checking signal at time frame 0.", mitk::Equal(0.0, m_output[0], 1e-6, true) == true);
+ CPPUNIT_ASSERT_MESSAGE("Checking signal at time frame 5.", mitk::Equal(0.085056, m_output[5], 1e-6, true) == true);
+ CPPUNIT_ASSERT_MESSAGE("Checking signal at time frame 10.", mitk::Equal(0.442948, m_output[10], 1e-6, true) == true);
+ CPPUNIT_ASSERT_MESSAGE("Checking signal at time frame 20.", mitk::Equal(0.254551, m_output[20], 1e-6, true) == true);
+ }
+
+ void ComputeDerivedParametersTest()
+ {
+ CPPUNIT_ASSERT_MESSAGE("Checking kep.", mitk::Equal(70.0, m_derivedParameters["kep"], 1e-6, true) == true);
+ }
+
+};
+
+MITK_TEST_SUITE_REGISTRATION(mitkStandardToftsModel)
diff --git a/Modules/Pharmacokinetics/test/mitkTwoCompartmentExchangeModelTest.cpp b/Modules/Pharmacokinetics/test/mitkTwoCompartmentExchangeModelTest.cpp
new file mode 100644
index 0000000000..652198ec20
--- /dev/null
+++ b/Modules/Pharmacokinetics/test/mitkTwoCompartmentExchangeModelTest.cpp
@@ -0,0 +1,137 @@
+/*============================================================================
+
+The Medical Imaging Interaction Toolkit (MITK)
+
+Copyright (c) German Cancer Research Center (DKFZ)
+All rights reserved.
+
+Use of this source code is governed by a 3-clause BSD license that can be
+found in the LICENSE file.
+
+============================================================================*/
+
+// Testing
+#include "mitkTestingMacros.h"
+#include "mitkTestFixture.h"
+
+//MITK includes
+#include "mitkVector.h"
+#include "mitkTwoCompartmentExchangeModel.h"
+#include "mitkAIFBasedModelBase.h"
+
+class mitkTwoCompartmentExchangeModelTestSuite : public mitk::TestFixture
+{
+ CPPUNIT_TEST_SUITE(mitkTwoCompartmentExchangeModelTestSuite);
+ MITK_TEST(GetModelDisplayNameTest);
+ MITK_TEST(GetModelTypeTest);
+ MITK_TEST(GetParameterNamesTest);
+ MITK_TEST(GetNumberOfParametersTest);
+ MITK_TEST(GetParameterUnitsTest);
+ MITK_TEST(ComputeModelfunctionTest);
+ CPPUNIT_TEST_SUITE_END();
+
+private:
+ mitk::TwoCompartmentExchangeModel::Pointer m_testmodel;
+ mitk::ModelBase::ModelResultType m_output;
+
+public:
+ void setUp() override
+ {
+ mitk::ModelBase::TimeGridType m_grid(22);
+ mitk::ModelBase::ParametersType m_testparameters(4);
+ mitk::AIFBasedModelBase::AterialInputFunctionType m_arterialInputFunction (22);
+
+ m_testparameters[mitk::TwoCompartmentExchangeModel::POSITION_PARAMETER_F] = 35.0;
+ m_testparameters(mitk::TwoCompartmentExchangeModel::POSITION_PARAMETER_PS) = 5.0;
+ m_testparameters(mitk::TwoCompartmentExchangeModel::POSITION_PARAMETER_ve) = 0.5;
+ m_testparameters(mitk::TwoCompartmentExchangeModel::POSITION_PARAMETER_vp) = 0.05;
+
+
+ for (int i = 0; i < 22; ++i)
+ {
+ // time grid in seconds, 14s between frames
+ m_grid[i] = (double)14 * i;
+ }
+
+ // AIF from Weinmann, H. J., Laniado, M., and W.Mützel (1984). Pharmacokinetics of GD - DTPA / dimeglumine after intravenous injection into healthy volunteers. Phys Chem Phys Med NMR, 16(2) : 167–72.
+ int D = 1;
+ double a1 = 3.99;
+ double m1 = 0.144;
+ double a2 = 4.78;
+ double m2 = 0.0111;
+
+ for (int i = 0; i < 22; ++i)
+ {
+ if (i < 5)
+ m_arterialInputFunction[i] = 0;
+ else
+ m_arterialInputFunction[i] = D * (a1 * exp(-m1 * m_grid[i]) + a2 * exp(-m2 * m_grid[i]));
+ }
+
+ m_testmodel = mitk::TwoCompartmentExchangeModel::New();
+ m_testmodel->SetTimeGrid(m_grid);
+ m_testmodel->SetAterialInputFunctionValues(m_arterialInputFunction);
+ m_testmodel->SetAterialInputFunctionTimeGrid(m_grid);
+
+ //ComputeModelfunction is called within GetSignal(), therefore no explicit testing of ComputeModelFunction()
+ m_output = m_testmodel->GetSignal(m_testparameters);
+ }
+ void tearDown() override
+ {
+ m_testmodel = nullptr;
+ m_output.clear();
+ }
+
+ void GetModelDisplayNameTest()
+ {
+ m_testmodel->GetModelDisplayName();
+ CPPUNIT_ASSERT_MESSAGE("Checking model display name.", m_testmodel->GetModelDisplayName() == "Two Compartment Exchange Model");
+ }
+
+
+ void GetModelTypeTest()
+ {
+ CPPUNIT_ASSERT_MESSAGE("Checking model type.", m_testmodel->GetModelType() == "Perfusion.MR");
+ }
+
+
+ void GetParameterNamesTest()
+ {
+ mitk::TwoCompartmentExchangeModel::ParameterNamesType parameterNames;
+ parameterNames.push_back("F");
+ parameterNames.push_back("PS");
+ parameterNames.push_back("ve");
+ parameterNames.push_back("vp");
+ CPPUNIT_ASSERT_MESSAGE("Checking parameter names.", m_testmodel->GetParameterNames() == parameterNames);
+ }
+
+
+ void GetNumberOfParametersTest()
+ {
+ CPPUNIT_ASSERT_MESSAGE("Checking number of parameters in model.", m_testmodel->GetNumberOfParameters() == 4);
+ }
+
+
+ void GetParameterUnitsTest()
+ {
+ mitk::TwoCompartmentExchangeModel::ParamterUnitMapType parameterUnits;
+ parameterUnits.insert(std::make_pair("F", "ml/min/100ml"));
+ parameterUnits.insert(std::make_pair("PS", "ml/min/100ml"));
+ parameterUnits.insert(std::make_pair("ve", "ml/ml"));
+ parameterUnits.insert(std::make_pair("vp", "ml/ml"));
+
+ CPPUNIT_ASSERT_MESSAGE("Checking parameter units.", m_testmodel->GetParameterUnits() == parameterUnits);
+ }
+
+ void ComputeModelfunctionTest()
+ {
+ CPPUNIT_ASSERT_MESSAGE("Checking signal at time frame 0.", mitk::Equal(0.0, m_output[0], 1e-6, true) == true);
+ CPPUNIT_ASSERT_MESSAGE("Checking signal at time frame 5.", mitk::Equal(0.057246, m_output[5], 1e-6, true) == true);
+ CPPUNIT_ASSERT_MESSAGE("Checking signal at time frame 10.", mitk::Equal(0.127806, m_output[10], 1e-6, true) == true);
+ CPPUNIT_ASSERT_MESSAGE("Checking signal at time frame 15.", mitk::Equal(0.131465, m_output[15], 1e-6, true) == true);
+ CPPUNIT_ASSERT_MESSAGE("Checking signal at time frame 20.", mitk::Equal(0.126101, m_output[20], 1e-6, true) == true);
+ }
+
+};
+
+MITK_TEST_SUITE_REGISTRATION(mitkTwoCompartmentExchangeModel)
diff --git a/Modules/PlanarFigure/include/mitkPlanarFigureInteractor.h b/Modules/PlanarFigure/include/mitkPlanarFigureInteractor.h
index 2e91c99d70..84a3f8892a 100644
--- a/Modules/PlanarFigure/include/mitkPlanarFigureInteractor.h
+++ b/Modules/PlanarFigure/include/mitkPlanarFigureInteractor.h
@@ -1,197 +1,198 @@
/*============================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.
Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.
============================================================================*/
#ifndef MITKPLANARFIGUREINTERACTOR_H
#define MITKPLANARFIGUREINTERACTOR_H
#include
#include "mitkCommon.h"
#include "mitkDataInteractor.h"
#include "mitkNumericTypes.h"
#pragma GCC visibility push(default)
#include
#pragma GCC visibility pop
namespace mitk
{
class DataNode;
class PlaneGeometry;
class PlanarFigure;
class PositionEvent;
class BaseRenderer;
class InteractionPositionEvent;
class StateMachineAction;
#pragma GCC visibility push(default)
// Define events for PlanarFigure interaction notifications
itkEventMacroDeclaration(PlanarFigureEvent, itk::AnyEvent);
itkEventMacroDeclaration(StartPlacementPlanarFigureEvent, PlanarFigureEvent);
itkEventMacroDeclaration(EndPlacementPlanarFigureEvent, PlanarFigureEvent);
itkEventMacroDeclaration(SelectPlanarFigureEvent, PlanarFigureEvent);
itkEventMacroDeclaration(StartInteractionPlanarFigureEvent, PlanarFigureEvent);
itkEventMacroDeclaration(EndInteractionPlanarFigureEvent, PlanarFigureEvent);
itkEventMacroDeclaration(StartHoverPlanarFigureEvent, PlanarFigureEvent);
itkEventMacroDeclaration(EndHoverPlanarFigureEvent, PlanarFigureEvent);
itkEventMacroDeclaration(ContextMenuPlanarFigureEvent, PlanarFigureEvent);
+ itkEventMacroDeclaration(PointMovedPlanarFigureEvent, PlanarFigureEvent);
#pragma GCC visibility pop
/**
* \brief Interaction with mitk::PlanarFigure objects via control-points
*
* @ingroup MitkPlanarFigureModule
*/
class MITKPLANARFIGURE_EXPORT PlanarFigureInteractor : public DataInteractor
{
public:
mitkClassMacro(PlanarFigureInteractor, DataInteractor);
itkFactorylessNewMacro(Self);
itkCloneMacro(Self);
/** \brief Sets the amount of precision */
void SetPrecision(ScalarType precision);
/** \brief Sets the minimal distance between two control points. */
void SetMinimumPointDistance(ScalarType minimumDistance);
protected:
PlanarFigureInteractor();
~PlanarFigureInteractor() override;
void ConnectActionsAndFunctions() override;
//////// Conditions ////////
bool CheckFigurePlaced(const InteractionEvent *interactionEvent);
bool CheckFigureHovering(const InteractionEvent *interactionEvent);
bool CheckControlPointHovering(const InteractionEvent *interactionEvent);
bool CheckSelection(const InteractionEvent *interactionEvent);
bool CheckPointValidity(const InteractionEvent *interactionEvent);
bool CheckFigureFinished(const InteractionEvent *interactionEvent);
bool CheckResetOnPointSelect(const InteractionEvent *interactionEvent);
bool CheckFigureOnRenderingGeometry(const InteractionEvent *interactionEvent);
bool CheckMinimalFigureFinished(const InteractionEvent *interactionEvent);
bool CheckFigureIsExtendable(const InteractionEvent *interactionEvent);
bool CheckFigureIsDeletable(const InteractionEvent *interactionEvent);
bool CheckFigureIsEditable(const InteractionEvent *interactionEvent);
//////// Actions ////////
void FinalizeFigure(StateMachineAction *, InteractionEvent *interactionEvent);
void MoveCurrentPoint(StateMachineAction *, InteractionEvent *interactionEvent);
void DeselectPoint(StateMachineAction *, InteractionEvent *interactionEvent);
void AddPoint(StateMachineAction *, InteractionEvent *interactionEvent);
void AddInitialPoint(StateMachineAction *, InteractionEvent *interactionEvent);
void StartHovering(StateMachineAction *, InteractionEvent *interactionEvent);
void EndHovering(StateMachineAction *, InteractionEvent *interactionEvent);
void DeleteFigure(StateMachineAction *, InteractionEvent *interactionEvent);
void PerformPointResetOnSelect(StateMachineAction *, InteractionEvent *interactionEvent);
void SetPreviewPointPosition(StateMachineAction *, InteractionEvent *interactionEvent);
void HidePreviewPoint(StateMachineAction *, InteractionEvent *interactionEvent);
void HideControlPoints(StateMachineAction *, InteractionEvent *interactionEvent);
void RemoveSelectedPoint(StateMachineAction *, InteractionEvent *interactionEvent);
void RequestContextMenu(StateMachineAction *, InteractionEvent *interactionEvent);
void SelectFigure(StateMachineAction *, InteractionEvent *interactionEvent);
void SelectPoint(StateMachineAction *, InteractionEvent *interactionEvent);
void EndInteraction(StateMachineAction *, InteractionEvent *interactionEvent);
bool FilterEvents(InteractionEvent *interactionEvent, DataNode *) override;
/**
\brief Used when clicking to determine if a point is too close to the previous point.
*/
bool IsMousePositionAcceptableAsNewControlPoint(const mitk::InteractionPositionEvent *positionEvent,
const PlanarFigure *);
bool TransformPositionEventToPoint2D(const InteractionPositionEvent *positionEvent,
const PlaneGeometry *planarFigureGeometry,
Point2D &point2D);
bool TransformObjectToDisplay(const mitk::Point2D &point2D,
mitk::Point2D &displayPoint,
const mitk::PlaneGeometry *objectGeometry,
const mitk::PlaneGeometry *rendererGeometry,
const mitk::BaseRenderer *renderer) const;
/** \brief Returns true if the first specified point is in proximity of the line defined
* the other two point; false otherwise.
*
* Proximity is defined as the rectangle around the line with pre-defined distance
* from the line. */
bool IsPointNearLine(const mitk::Point2D &point,
const mitk::Point2D &startPoint,
const mitk::Point2D &endPoint,
mitk::Point2D &projectedPoint) const;
/** \brief Returns true if the point contained in the passed event (in display coordinates)
* is over the planar figure (with a pre-defined tolerance range); false otherwise. */
int IsPositionOverFigure(const InteractionPositionEvent *positionEvent,
PlanarFigure *planarFigure,
const PlaneGeometry *planarFigureGeometry,
const PlaneGeometry *rendererGeometry,
Point2D &pointProjectedOntoLine) const;
/** \brief Returns the index of the marker (control point) over which the point contained
* in the passed event (in display coordinates) currently is; -1 if the point is not over
* a marker. */
int IsPositionInsideMarker(const InteractionPositionEvent *positionEvent,
const PlanarFigure *planarFigure,
const PlaneGeometry *planarFigureGeometry,
const PlaneGeometry *rendererGeometry,
const BaseRenderer *renderer) const;
void LogPrintPlanarFigureQuantities(const PlanarFigure *planarFigure);
void ConfigurationChanged() override;
private:
/** \brief to store the value of precision to pick a point */
ScalarType m_Precision;
/** \brief Store the minimal distance between two control points. */
ScalarType m_MinimumPointDistance;
/** \brief True if the mouse is currently hovering over the image. */
bool m_IsHovering;
};
}
#endif // MITKPLANARFIGUREINTERACTOR_H
diff --git a/Modules/PlanarFigure/src/Interactions/mitkPlanarFigureInteractor.cpp b/Modules/PlanarFigure/src/Interactions/mitkPlanarFigureInteractor.cpp
index 42916486c3..9556791b3f 100644
--- a/Modules/PlanarFigure/src/Interactions/mitkPlanarFigureInteractor.cpp
+++ b/Modules/PlanarFigure/src/Interactions/mitkPlanarFigureInteractor.cpp
@@ -1,1126 +1,1129 @@
/*============================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.
Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.
============================================================================*/
#define PLANARFIGUREINTERACTOR_DBG MITK_DEBUG("PlanarFigureInteractor") << __LINE__ << ": "
#include "mitkPlanarFigureInteractor.h"
#include "mitkPlanarBezierCurve.h"
#include "mitkPlanarCircle.h"
#include "mitkPlanarFigure.h"
#include "mitkPlanarPolygon.h"
#include "mitkInteractionPositionEvent.h"
#include "mitkInternalEvent.h"
#include "mitkBaseRenderer.h"
#include "mitkRenderingManager.h"
#include "mitkAbstractTransformGeometry.h"
#include "mitkPlaneGeometry.h"
namespace mitk
{
itkEventMacroDefinition(PlanarFigureEvent, itk::AnyEvent);
itkEventMacroDefinition(StartPlacementPlanarFigureEvent, PlanarFigureEvent);
itkEventMacroDefinition(EndPlacementPlanarFigureEvent, PlanarFigureEvent);
itkEventMacroDefinition(SelectPlanarFigureEvent, PlanarFigureEvent);
itkEventMacroDefinition(StartInteractionPlanarFigureEvent, PlanarFigureEvent);
itkEventMacroDefinition(EndInteractionPlanarFigureEvent, PlanarFigureEvent);
itkEventMacroDefinition(StartHoverPlanarFigureEvent, PlanarFigureEvent);
itkEventMacroDefinition(EndHoverPlanarFigureEvent, PlanarFigureEvent);
itkEventMacroDefinition(ContextMenuPlanarFigureEvent, PlanarFigureEvent);
+ itkEventMacroDefinition(PointMovedPlanarFigureEvent, PlanarFigureEvent);
}
mitk::PlanarFigureInteractor::PlanarFigureInteractor()
: DataInteractor()
, m_Precision(6.5)
, m_MinimumPointDistance(25.0)
, m_IsHovering(false)
{
}
mitk::PlanarFigureInteractor::~PlanarFigureInteractor()
{
}
void mitk::PlanarFigureInteractor::ConnectActionsAndFunctions()
{
CONNECT_CONDITION("figure_is_on_current_slice", CheckFigureOnRenderingGeometry);
CONNECT_CONDITION("figure_is_placed", CheckFigurePlaced);
CONNECT_CONDITION("minimal_figure_is_finished", CheckMinimalFigureFinished);
CONNECT_CONDITION("hovering_above_figure", CheckFigureHovering);
CONNECT_CONDITION("hovering_above_point", CheckControlPointHovering);
CONNECT_CONDITION("figure_is_selected", CheckSelection);
CONNECT_CONDITION("point_is_valid", CheckPointValidity);
CONNECT_CONDITION("figure_is_finished", CheckFigureFinished);
CONNECT_CONDITION("reset_on_point_select_needed", CheckResetOnPointSelect);
CONNECT_CONDITION("points_can_be_added_or_removed", CheckFigureIsExtendable);
CONNECT_CONDITION("figure_can_be_deleted", CheckFigureIsDeletable);
CONNECT_CONDITION("figure_is_editable", CheckFigureIsEditable);
CONNECT_FUNCTION("finalize_figure", FinalizeFigure);
CONNECT_FUNCTION("hide_preview_point", HidePreviewPoint)
CONNECT_FUNCTION("hide_control_points", HideControlPoints)
CONNECT_FUNCTION("set_preview_point_position", SetPreviewPointPosition)
CONNECT_FUNCTION("move_current_point", MoveCurrentPoint);
CONNECT_FUNCTION("deselect_point", DeselectPoint);
CONNECT_FUNCTION("add_new_point", AddPoint);
CONNECT_FUNCTION("add_initial_point", AddInitialPoint);
CONNECT_FUNCTION("remove_selected_point", RemoveSelectedPoint);
CONNECT_FUNCTION("request_context_menu", RequestContextMenu);
CONNECT_FUNCTION("select_figure", SelectFigure);
CONNECT_FUNCTION("select_point", SelectPoint);
CONNECT_FUNCTION("end_interaction", EndInteraction);
CONNECT_FUNCTION("start_hovering", StartHovering)
CONNECT_FUNCTION("end_hovering", EndHovering);
CONNECT_FUNCTION("delete_figure", DeleteFigure);
CONNECT_FUNCTION("reset_on_point_select", PerformPointResetOnSelect);
}
bool mitk::PlanarFigureInteractor::CheckFigurePlaced(const InteractionEvent * /*interactionEvent*/)
{
auto planarFigure = dynamic_cast(GetDataNode()->GetData());
if (nullptr == planarFigure)
{
return false;
}
bool isFigureFinished = false;
planarFigure->GetPropertyList()->GetBoolProperty("initiallyplaced", isFigureFinished);
return planarFigure->IsPlaced() && isFigureFinished;
}
void mitk::PlanarFigureInteractor::MoveCurrentPoint(StateMachineAction *, InteractionEvent *interactionEvent)
{
auto positionEvent = dynamic_cast(interactionEvent);
if (nullptr == positionEvent)
{
return;
}
bool isEditable = true;
GetDataNode()->GetBoolProperty("planarfigure.iseditable", isEditable);
auto planarFigure = dynamic_cast(GetDataNode()->GetData());
if (nullptr == planarFigure)
{
return;
}
auto planarFigureGeometry = planarFigure->GetPlaneGeometry();
if (nullptr == planarFigureGeometry)
{
return;
}
auto abstractTransformGeometry = dynamic_cast(planarFigure->GetGeometry(0));
if (nullptr != abstractTransformGeometry)
{
return;
}
// Extract point in 2D world coordinates (relative to PlaneGeometry of PlanarFigure)
Point2D point2D;
if (!this->TransformPositionEventToPoint2D(positionEvent, planarFigureGeometry, point2D) || !isEditable)
{
return;
}
planarFigure->InvokeEvent(StartInteractionPlanarFigureEvent());
// check if the control points shall be hidden during interaction
bool hidecontrolpointsduringinteraction = false;
GetDataNode()->GetBoolProperty("planarfigure.hidecontrolpointsduringinteraction", hidecontrolpointsduringinteraction);
// hide the control points if necessary
// interactionEvent->GetSender()->GetDataStorage()->BlockNodeModifiedEvents( true );
GetDataNode()->SetBoolProperty("planarfigure.drawcontrolpoints", !hidecontrolpointsduringinteraction);
// interactionEvent->GetSender()->GetDataStorage()->BlockNodeModifiedEvents( false );
// Move current control point to this point
planarFigure->SetCurrentControlPoint(point2D);
// Re-evaluate features
planarFigure->EvaluateFeatures();
// Update rendered scene
RenderingManager::GetInstance()->RequestUpdateAll();
+
+ planarFigure->InvokeEvent(PointMovedPlanarFigureEvent());
}
void mitk::PlanarFigureInteractor::FinalizeFigure(StateMachineAction *, InteractionEvent *)
{
auto planarFigure = dynamic_cast(GetDataNode()->GetData());
if (nullptr == planarFigure)
{
return;
}
planarFigure->Modified();
planarFigure->DeselectControlPoint();
planarFigure->RemoveLastControlPoint();
planarFigure->SetProperty("initiallyplaced", mitk::BoolProperty::New(true));
GetDataNode()->SetBoolProperty("planarfigure.drawcontrolpoints", true);
GetDataNode()->Modified();
planarFigure->InvokeEvent(EndPlacementPlanarFigureEvent());
planarFigure->InvokeEvent(EndInteractionPlanarFigureEvent());
// Shape might change when figure is finalized, e.g., smoothing of subdivision polygon
planarFigure->EvaluateFeatures();
RenderingManager::GetInstance()->RequestUpdateAll();
}
void mitk::PlanarFigureInteractor::EndInteraction(StateMachineAction *, InteractionEvent *)
{
auto planarFigure = dynamic_cast(GetDataNode()->GetData());
if (nullptr == planarFigure)
{
return;
}
GetDataNode()->SetBoolProperty("planarfigure.drawcontrolpoints", true);
planarFigure->Modified();
planarFigure->InvokeEvent(EndInteractionPlanarFigureEvent());
RenderingManager::GetInstance()->RequestUpdateAll();
}
bool mitk::PlanarFigureInteractor::FilterEvents(InteractionEvent *interactionEvent, mitk::DataNode * /*dataNode*/)
{
if (interactionEvent->GetSender() == nullptr)
return false;
if (interactionEvent->GetSender()->GetMapperID() == BaseRenderer::Standard3D)
return false;
return true;
}
void mitk::PlanarFigureInteractor::EndHovering(StateMachineAction *, InteractionEvent *)
{
auto planarFigure = dynamic_cast(GetDataNode()->GetData());
if (nullptr == planarFigure)
{
return;
}
planarFigure->ResetPreviewContolPoint();
// Invoke end-hover event once the mouse is exiting the figure area
m_IsHovering = false;
planarFigure->InvokeEvent(EndHoverPlanarFigureEvent());
// Set bool property to indicate that planar figure is no longer in "hovering" mode
GetDataNode()->SetBoolProperty("planarfigure.ishovering", false);
RenderingManager::GetInstance()->RequestUpdateAll();
}
void mitk::PlanarFigureInteractor::DeleteFigure(StateMachineAction *, InteractionEvent *interactionEvent)
{
auto planarFigure = dynamic_cast(GetDataNode()->GetData());
if (nullptr == planarFigure)
{
return;
}
planarFigure->RemoveAllObservers();
GetDataNode()->RemoveAllObservers();
interactionEvent->GetSender()->GetDataStorage()->Remove(GetDataNode());
RenderingManager::GetInstance()->RequestUpdateAll();
}
void mitk::PlanarFigureInteractor::PerformPointResetOnSelect(StateMachineAction *, InteractionEvent *)
{
auto planarFigure = dynamic_cast(GetDataNode()->GetData());
if (nullptr == planarFigure)
{
return;
}
planarFigure->ResetOnPointSelect();
}
bool mitk::PlanarFigureInteractor::CheckMinimalFigureFinished(const InteractionEvent * /*interactionEvent*/)
{
auto planarFigure = dynamic_cast(GetDataNode()->GetData());
if (nullptr == planarFigure)
{
return false;
}
return planarFigure->GetNumberOfControlPoints() >= planarFigure->GetMinimumNumberOfControlPoints();
}
bool mitk::PlanarFigureInteractor::CheckFigureFinished(const InteractionEvent * /*interactionEvent*/)
{
auto planarFigure = dynamic_cast(GetDataNode()->GetData());
if (nullptr == planarFigure)
{
return false;
}
return planarFigure->GetNumberOfControlPoints() >= planarFigure->GetMaximumNumberOfControlPoints();
}
bool mitk::PlanarFigureInteractor::CheckFigureIsExtendable(const InteractionEvent * /*interactionEvent*/)
{
bool isExtendable(false);
GetDataNode()->GetBoolProperty("planarfigure.isextendable", isExtendable);
return isExtendable;
}
bool mitk::PlanarFigureInteractor::CheckFigureIsDeletable(const InteractionEvent * /*interactionEvent*/)
{
bool isDeletable(true);
GetDataNode()->GetBoolProperty("planarfigure.isdeletable", isDeletable);
return isDeletable;
}
bool mitk::PlanarFigureInteractor::CheckFigureIsEditable(const InteractionEvent * /*interactionEvent*/)
{
bool isEditable(true);
GetDataNode()->GetBoolProperty("planarfigure.iseditable", isEditable);
return isEditable;
}
void mitk::PlanarFigureInteractor::DeselectPoint(StateMachineAction *, InteractionEvent * /*interactionEvent*/)
{
auto planarFigure = dynamic_cast(GetDataNode()->GetData());
if (nullptr == planarFigure)
{
return;
}
const bool wasSelected = planarFigure->DeselectControlPoint();
if (wasSelected)
{
// Issue event so that listeners may update themselves
planarFigure->Modified();
planarFigure->InvokeEvent(EndInteractionPlanarFigureEvent());
GetDataNode()->SetBoolProperty("planarfigure.drawcontrolpoints", true);
GetDataNode()->Modified();
}
}
void mitk::PlanarFigureInteractor::AddPoint(StateMachineAction *, InteractionEvent *interactionEvent)
{
auto positionEvent = dynamic_cast(interactionEvent);
if (nullptr == positionEvent)
{
return;
}
/*
* Added check for "initiallyplaced" due to bug 13097:
*
* There are two possible cases in which a point can be inserted into a PlanarPolygon:
*
* 1. The figure is currently drawn -> the point will be appended at the end of the figure
* 2. A point is inserted at a userdefined position after the initial placement of the figure is finished
*
* In the second case we need to determine the proper insertion index. In the first case the index always has
* to be -1 so that the point is appended to the end.
*
* These changes are necessary because of a macOS specific issue: If a users draws a PlanarPolygon then the
* next point to be added moves according to the mouse position. If then the user left clicks in order to add
* a point one would assume the last move position is identical to the left click position. This is actually the
* case for windows and linux but somehow NOT for mac. Because of the insertion logic of a new point in the
* PlanarFigure then for mac the wrong current selected point is determined.
*
* With this check here this problem can be avoided. However a redesign of the insertion logic should be considered
*/
const DataNode::Pointer node = this->GetDataNode();
const BaseData::Pointer data = node->GetData();
bool isFigureFinished = false;
data->GetPropertyList()->GetBoolProperty("initiallyplaced", isFigureFinished);
bool selected = false;
bool isEditable = true;
node->GetBoolProperty("selected", selected);
node->GetBoolProperty("planarfigure.iseditable", isEditable);
if (!selected || !isEditable)
{
return;
}
auto planarFigure = dynamic_cast(data.GetPointer());
if (nullptr == planarFigure)
{
return;
}
// We can't derive a new control point from a polyline of a Bezier curve
// as all control points contribute to each polyline point.
if (dynamic_cast(planarFigure) != nullptr && isFigureFinished)
return;
auto planarFigureGeometry = planarFigure->GetPlaneGeometry();
if (nullptr == planarFigureGeometry)
{
return;
}
auto abstractTransformGeometry = dynamic_cast(planarFigure->GetGeometry(0));
if (nullptr != abstractTransformGeometry)
{
return;
}
// If the planarFigure already has reached the maximum number
if (planarFigure->GetNumberOfControlPoints() >= planarFigure->GetMaximumNumberOfControlPoints())
{
return;
}
// Extract point in 2D world coordinates (relative to PlaneGeometry of
// PlanarFigure)
Point2D point2D, projectedPoint;
if (!this->TransformPositionEventToPoint2D(positionEvent, planarFigureGeometry, point2D))
{
return;
}
// TODO: check segment of polyline we clicked in
int nextIndex = -1;
// We only need to check which position to insert the control point
// when interacting with a PlanarPolygon. For all other types
// new control points will always be appended
const mitk::BaseRenderer *renderer = interactionEvent->GetSender();
const PlaneGeometry *projectionPlane = renderer->GetCurrentWorldPlaneGeometry();
if (dynamic_cast(planarFigure) && isFigureFinished)
{
nextIndex =
this->IsPositionOverFigure(positionEvent, planarFigure, planarFigureGeometry, projectionPlane, projectedPoint);
}
// Add point as new control point
if (planarFigure->IsPreviewControlPointVisible())
{
point2D = planarFigure->GetPreviewControlPoint();
}
planarFigure->AddControlPoint(point2D, planarFigure->GetControlPointForPolylinePoint(nextIndex, 0));
if (planarFigure->IsPreviewControlPointVisible())
{
planarFigure->SelectControlPoint(nextIndex);
planarFigure->ResetPreviewContolPoint();
}
// Re-evaluate features
planarFigure->EvaluateFeatures();
// this->LogPrintPlanarFigureQuantities( planarFigure );
// Update rendered scene
RenderingManager::GetInstance()->RequestUpdateAll();
}
void mitk::PlanarFigureInteractor::AddInitialPoint(StateMachineAction *, InteractionEvent *interactionEvent)
{
auto positionEvent = dynamic_cast(interactionEvent);
if (nullptr == positionEvent)
{
return;
}
auto planarFigure = dynamic_cast(GetDataNode()->GetData());
if (nullptr == planarFigure)
{
return;
}
mitk::BaseRenderer *renderer = interactionEvent->GetSender();
auto abstractTransformGeometry = dynamic_cast(planarFigure->GetGeometry(0));
// Invoke event to notify listeners that placement of this PF starts now
planarFigure->InvokeEvent(StartPlacementPlanarFigureEvent());
// Use PlaneGeometry of the renderer clicked on for this PlanarFigure
auto *planeGeometry = const_cast(
dynamic_cast(renderer->GetSliceNavigationController()->GetCurrentPlaneGeometry()));
if (planeGeometry != nullptr && abstractTransformGeometry == nullptr)
{
planarFigure->SetPlaneGeometry(planeGeometry);
}
else
{
return;
}
// Extract point in 2D world coordinates (relative to PlaneGeometry of
// PlanarFigure)
Point2D point2D;
if (!this->TransformPositionEventToPoint2D(positionEvent, planeGeometry, point2D))
{
return;
}
// Place PlanarFigure at this point
planarFigure->PlaceFigure(point2D);
// Re-evaluate features
planarFigure->EvaluateFeatures();
// this->LogPrintPlanarFigureQuantities( planarFigure );
// Set a bool property indicating that the figure has been placed in
// the current RenderWindow. This is required so that the same render
// window can be re-aligned to the PlaneGeometry of the PlanarFigure later
// on in an application.
GetDataNode()->SetBoolProperty("PlanarFigureInitializedWindow", true, renderer);
// Update rendered scene
RenderingManager::GetInstance()->RequestUpdateAll();
}
void mitk::PlanarFigureInteractor::StartHovering(StateMachineAction *, InteractionEvent *interactionEvent)
{
auto positionEvent = dynamic_cast(interactionEvent);
if (nullptr == positionEvent)
{
return;
}
auto planarFigure = dynamic_cast(GetDataNode()->GetData());
if (nullptr == planarFigure)
{
return;
}
if (!m_IsHovering)
{
// Invoke hover event once when the mouse is entering the figure area
m_IsHovering = true;
planarFigure->InvokeEvent(StartHoverPlanarFigureEvent());
// Set bool property to indicate that planar figure is currently in "hovering" mode
GetDataNode()->SetBoolProperty("planarfigure.ishovering", true);
RenderingManager::GetInstance()->RequestUpdateAll();
}
}
void mitk::PlanarFigureInteractor::SetPreviewPointPosition(StateMachineAction *, InteractionEvent *interactionEvent)
{
auto positionEvent = dynamic_cast(interactionEvent);
if (nullptr == positionEvent)
{
return;
}
auto planarFigure = dynamic_cast(GetDataNode()->GetData());
if (nullptr == planarFigure)
{
return;
}
const mitk::BaseRenderer *renderer = interactionEvent->GetSender();
planarFigure->DeselectControlPoint();
mitk::Point2D pointProjectedOntoLine = positionEvent->GetPointerPositionOnScreen();
bool selected(false);
bool isExtendable(false);
bool isEditable(true);
GetDataNode()->GetBoolProperty("selected", selected);
GetDataNode()->GetBoolProperty("planarfigure.isextendable", isExtendable);
GetDataNode()->GetBoolProperty("planarfigure.iseditable", isEditable);
if (selected && isExtendable && isEditable)
{
renderer->DisplayToPlane(pointProjectedOntoLine, pointProjectedOntoLine);
planarFigure->SetPreviewControlPoint(pointProjectedOntoLine);
}
RenderingManager::GetInstance()->RequestUpdateAll();
}
void mitk::PlanarFigureInteractor::HideControlPoints(StateMachineAction *, InteractionEvent * /*interactionEvent*/)
{
GetDataNode()->SetBoolProperty("planarfigure.drawcontrolpoints", false);
}
void mitk::PlanarFigureInteractor::HidePreviewPoint(StateMachineAction *, InteractionEvent *)
{
auto planarFigure = dynamic_cast(GetDataNode()->GetData());
if (nullptr == planarFigure)
{
return;
}
planarFigure->ResetPreviewContolPoint();
RenderingManager::GetInstance()->RequestUpdateAll();
}
bool mitk::PlanarFigureInteractor::CheckFigureHovering(const InteractionEvent *interactionEvent)
{
auto positionEvent = dynamic_cast(interactionEvent);
if (nullptr == positionEvent)
{
return false;
}
auto planarFigure = dynamic_cast(GetDataNode()->GetData());
if (nullptr == planarFigure)
{
return false;
}
auto planarFigureGeometry = planarFigure->GetPlaneGeometry();
if (nullptr == planarFigureGeometry)
{
return false;
}
auto abstractTransformGeometry = dynamic_cast(planarFigure->GetGeometry(0));
if (nullptr != abstractTransformGeometry)
{
return false;
}
const mitk::BaseRenderer *renderer = interactionEvent->GetSender();
const PlaneGeometry *projectionPlane = renderer->GetCurrentWorldPlaneGeometry();
mitk::Point2D pointProjectedOntoLine;
int previousControlPoint = this->IsPositionOverFigure(
positionEvent, planarFigure, planarFigureGeometry, projectionPlane, pointProjectedOntoLine);
bool isHovering = (previousControlPoint != -1);
return isHovering;
}
bool mitk::PlanarFigureInteractor::CheckControlPointHovering(const InteractionEvent *interactionEvent)
{
auto positionEvent = dynamic_cast(interactionEvent);
if (nullptr == positionEvent)
{
return false;
}
auto planarFigure = dynamic_cast(GetDataNode()->GetData());
if (nullptr == planarFigure)
{
return false;
}
auto planarFigureGeometry = planarFigure->GetPlaneGeometry();
if (nullptr == planarFigureGeometry)
{
return false;
}
auto abstractTransformGeometry = dynamic_cast(planarFigure->GetGeometry(0));
if (nullptr != abstractTransformGeometry)
{
return false;
}
const mitk::BaseRenderer *renderer = interactionEvent->GetSender();
const PlaneGeometry *projectionPlane = renderer->GetCurrentWorldPlaneGeometry();
int pointIndex = -1;
pointIndex = mitk::PlanarFigureInteractor::IsPositionInsideMarker(
positionEvent, planarFigure, planarFigureGeometry, projectionPlane, renderer);
return pointIndex >= 0;
}
bool mitk::PlanarFigureInteractor::CheckSelection(const InteractionEvent * /*interactionEvent*/)
{
bool selected = false;
GetDataNode()->GetBoolProperty("selected", selected);
return selected;
}
void mitk::PlanarFigureInteractor::SelectFigure(StateMachineAction *, InteractionEvent * /*interactionEvent*/)
{
auto planarFigure = dynamic_cast(GetDataNode()->GetData());
if (nullptr == planarFigure)
{
return;
}
planarFigure->InvokeEvent(SelectPlanarFigureEvent());
}
void mitk::PlanarFigureInteractor::SelectPoint(StateMachineAction *, InteractionEvent *interactionEvent)
{
auto positionEvent = dynamic_cast(interactionEvent);
if (nullptr == positionEvent)
{
return;
}
auto planarFigure = dynamic_cast(GetDataNode()->GetData());
if (nullptr == planarFigure)
{
return;
}
auto planarFigureGeometry = planarFigure->GetPlaneGeometry();
if (nullptr == planarFigureGeometry)
{
return;
}
auto abstractTransformGeometry = dynamic_cast(planarFigure->GetGeometry(0));
if (nullptr != abstractTransformGeometry)
{
return;
}
const mitk::BaseRenderer *renderer = interactionEvent->GetSender();
const PlaneGeometry *projectionPlane = renderer->GetCurrentWorldPlaneGeometry();
const int pointIndex = mitk::PlanarFigureInteractor::IsPositionInsideMarker(
positionEvent, planarFigure, planarFigureGeometry, projectionPlane, renderer);
if (pointIndex >= 0)
{
// If mouse is above control point, mark it as selected
planarFigure->SelectControlPoint(pointIndex);
}
else
{
planarFigure->DeselectControlPoint();
}
}
bool mitk::PlanarFigureInteractor::CheckPointValidity(const InteractionEvent *interactionEvent)
{
// Check if the distance of the current point to the previously set point in display coordinates
// is sufficient (if a previous point exists)
auto positionEvent = dynamic_cast(interactionEvent);
if (nullptr == positionEvent)
{
return false;
}
auto planarFigure = dynamic_cast(GetDataNode()->GetData());
if (nullptr == planarFigure)
{
return false;
}
return IsMousePositionAcceptableAsNewControlPoint(positionEvent, planarFigure);
}
void mitk::PlanarFigureInteractor::RemoveSelectedPoint(StateMachineAction *, InteractionEvent *interactionEvent)
{
auto planarFigure = dynamic_cast(GetDataNode()->GetData());
if (nullptr == planarFigure)
{
return;
}
const int selectedControlPoint = planarFigure->GetSelectedControlPoint();
planarFigure->RemoveControlPoint(selectedControlPoint);
// Re-evaluate features
planarFigure->EvaluateFeatures();
planarFigure->Modified();
GetDataNode()->SetBoolProperty("planarfigure.drawcontrolpoints", true);
planarFigure->InvokeEvent(EndInteractionPlanarFigureEvent());
RenderingManager::GetInstance()->RequestUpdateAll();
mitk::BaseRenderer *renderer = interactionEvent->GetSender();
HandleEvent(mitk::InternalEvent::New(renderer, this, "Dummy-Event"), GetDataNode());
}
void mitk::PlanarFigureInteractor::RequestContextMenu(StateMachineAction *, InteractionEvent * /*interactionEvent*/)
{
auto planarFigure = dynamic_cast(GetDataNode()->GetData());
if (nullptr == planarFigure)
{
return;
}
bool selected = false;
GetDataNode()->GetBoolProperty("selected", selected);
// no need to invoke this if the figure is already selected
if (!selected)
{
planarFigure->InvokeEvent(SelectPlanarFigureEvent());
}
planarFigure->InvokeEvent(ContextMenuPlanarFigureEvent());
}
bool mitk::PlanarFigureInteractor::CheckResetOnPointSelect(const InteractionEvent * /*interactionEvent*/)
{
auto planarFigure = dynamic_cast(GetDataNode()->GetData());
if (nullptr == planarFigure)
{
return false;
}
bool isEditable = true;
GetDataNode()->GetBoolProperty("planarfigure.iseditable", isEditable);
// Reset the PlanarFigure if required
return isEditable && planarFigure->ResetOnPointSelectNeeded();
}
bool mitk::PlanarFigureInteractor::CheckFigureOnRenderingGeometry(const InteractionEvent *interactionEvent)
{
auto positionEvent = dynamic_cast(interactionEvent);
if (nullptr == positionEvent)
{
return false;
}
const mitk::Point3D worldPoint3D = positionEvent->GetPositionInWorld();
auto planarFigure = dynamic_cast(GetDataNode()->GetData());
if (nullptr == planarFigure)
{
return false;
}
auto planarFigureGeometry = planarFigure->GetPlaneGeometry();
if (nullptr == planarFigureGeometry)
{
return false;
}
auto abstractTransformGeometry = dynamic_cast(planarFigure->GetGeometry(0));
if (nullptr != abstractTransformGeometry)
{
return false;
}
const double planeThickness = planarFigureGeometry->GetExtentInMM(2);
return planarFigureGeometry->Distance(worldPoint3D) <= planeThickness;
}
void mitk::PlanarFigureInteractor::SetPrecision(mitk::ScalarType precision)
{
m_Precision = precision;
}
void mitk::PlanarFigureInteractor::SetMinimumPointDistance(ScalarType minimumDistance)
{
m_MinimumPointDistance = minimumDistance;
}
bool mitk::PlanarFigureInteractor::TransformPositionEventToPoint2D(const InteractionPositionEvent *positionEvent,
const PlaneGeometry *planarFigureGeometry,
Point2D &point2D)
{
if (nullptr == positionEvent || nullptr == planarFigureGeometry)
{
return false;
}
const mitk::Point3D worldPoint3D = positionEvent->GetPositionInWorld();
// TODO: proper handling of distance tolerance
if (planarFigureGeometry->Distance(worldPoint3D) > 0.1)
{
return false;
}
// Project point onto plane of this PlanarFigure
planarFigureGeometry->Map(worldPoint3D, point2D);
return true;
}
bool mitk::PlanarFigureInteractor::TransformObjectToDisplay(const mitk::Point2D &point2D,
mitk::Point2D &displayPoint,
const mitk::PlaneGeometry *objectGeometry,
const mitk::PlaneGeometry *rendererGeometry,
const mitk::BaseRenderer *renderer) const
{
if (nullptr == objectGeometry || nullptr == rendererGeometry || nullptr == renderer)
{
return false;
}
mitk::Point3D point3D;
// Map circle point from local 2D geometry into 3D world space
objectGeometry->Map(point2D, point3D);
const double planeThickness = objectGeometry->GetExtentInMM(2);
// TODO: proper handling of distance tolerance
if (rendererGeometry->Distance(point3D) < planeThickness / 3.0)
{
// Project 3D world point onto display geometry
renderer->WorldToDisplay(point3D, displayPoint);
return true;
}
return false;
}
bool mitk::PlanarFigureInteractor::IsPointNearLine(const mitk::Point2D &point,
const mitk::Point2D &startPoint,
const mitk::Point2D &endPoint,
mitk::Point2D &projectedPoint) const
{
mitk::Vector2D n1 = endPoint - startPoint;
n1.Normalize();
// Determine dot products between line vector and startpoint-point / endpoint-point vectors
const double l1 = n1 * (point - startPoint);
const double l2 = -n1 * (point - endPoint);
// Determine projection of specified point onto line defined by start / end point
const mitk::Point2D crossPoint = startPoint + n1 * l1;
projectedPoint = crossPoint;
const float dist1 = crossPoint.SquaredEuclideanDistanceTo(point);
const float dist2 = endPoint.SquaredEuclideanDistanceTo(point);
const float dist3 = startPoint.SquaredEuclideanDistanceTo(point);
// Point is inside encompassing rectangle IF
// - its distance to its projected point is small enough
// - it is not further outside of the line than the defined tolerance
if (((dist1 < 20.0) && (l1 > 0.0) && (l2 > 0.0)) || dist2 < 20.0 || dist3 < 20.0)
{
return true;
}
return false;
}
int mitk::PlanarFigureInteractor::IsPositionOverFigure(const InteractionPositionEvent *positionEvent,
PlanarFigure *planarFigure,
const PlaneGeometry *planarFigureGeometry,
const PlaneGeometry *rendererGeometry,
Point2D &pointProjectedOntoLine) const
{
if (nullptr == positionEvent || nullptr == planarFigure || nullptr == planarFigureGeometry
|| nullptr == rendererGeometry)
{
return -1;
}
mitk::Point2D displayPosition = positionEvent->GetPointerPositionOnScreen();
// Iterate over all polylines of planar figure, and check if
// any one is close to the current display position
typedef mitk::PlanarFigure::PolyLineType VertexContainerType;
Point2D polyLinePoint;
Point2D firstPolyLinePoint;
Point2D previousPolyLinePoint;
for (unsigned short loop = 0; loop < planarFigure->GetPolyLinesSize(); ++loop)
{
const VertexContainerType polyLine = planarFigure->GetPolyLine(loop);
bool firstPoint(true);
for (auto it = polyLine.begin(); it != polyLine.end(); ++it)
{
// Get plane coordinates of this point of polyline (if possible)
if (!this->TransformObjectToDisplay(
*it, polyLinePoint, planarFigureGeometry, rendererGeometry, positionEvent->GetSender()))
{
break; // Poly line invalid (not on current 2D plane) --> skip it
}
if (firstPoint)
{
firstPolyLinePoint = polyLinePoint;
firstPoint = false;
}
else if (this->IsPointNearLine(displayPosition, previousPolyLinePoint, polyLinePoint, pointProjectedOntoLine))
{
// Point is close enough to line segment --> Return index of the segment
return std::distance(polyLine.begin(), it);
}
previousPolyLinePoint = polyLinePoint;
}
// For closed figures, also check last line segment
if (planarFigure->IsClosed() &&
this->IsPointNearLine(displayPosition, polyLinePoint, firstPolyLinePoint, pointProjectedOntoLine))
{
return 0; // Return index of first control point
}
}
return -1;
}
int mitk::PlanarFigureInteractor::IsPositionInsideMarker(const InteractionPositionEvent *positionEvent,
const PlanarFigure *planarFigure,
const PlaneGeometry *planarFigureGeometry,
const PlaneGeometry *rendererGeometry,
const BaseRenderer *renderer) const
{
if (nullptr == positionEvent || nullptr == planarFigure || nullptr == planarFigureGeometry
|| nullptr == rendererGeometry || nullptr == renderer)
{
return -1;
}
const mitk::Point2D displayPosition = positionEvent->GetPointerPositionOnScreen();
// Iterate over all control points of planar figure, and check if
// any one is close to the current display position
mitk::Point2D displayControlPoint;
const int numberOfControlPoints = planarFigure->GetNumberOfControlPoints();
for (int i = 0; i < numberOfControlPoints; i++)
{
if (this->TransformObjectToDisplay(
planarFigure->GetControlPoint(i), displayControlPoint, planarFigureGeometry, rendererGeometry, renderer))
{
// TODO: variable size of markers
if (displayPosition.SquaredEuclideanDistanceTo(displayControlPoint) < 20.0)
{
return i;
}
}
}
return -1;
}
void mitk::PlanarFigureInteractor::LogPrintPlanarFigureQuantities(const PlanarFigure *planarFigure)
{
if (nullptr == planarFigure)
{
MITK_INFO << "PlanarFigure invalid.";
}
MITK_INFO << "PlanarFigure: " << planarFigure->GetNameOfClass();
for (unsigned int i = 0; i < planarFigure->GetNumberOfFeatures(); ++i)
{
MITK_INFO << "* " << planarFigure->GetFeatureName(i) << ": " << planarFigure->GetQuantity(i) << " "
<< planarFigure->GetFeatureUnit(i);
}
}
bool mitk::PlanarFigureInteractor::IsMousePositionAcceptableAsNewControlPoint(
const mitk::InteractionPositionEvent *positionEvent, const PlanarFigure *planarFigure)
{
if (nullptr == positionEvent || nullptr == planarFigure)
{
return false;
}
const BaseRenderer *renderer = positionEvent->GetSender();
if (nullptr == renderer)
{
return false;
}
// Get the timestep to support 3D+t
const int timeStep(renderer->GetTimeStep(planarFigure));
bool tooClose(false);
auto planarFigureGeometry = dynamic_cast(planarFigure->GetGeometry(timeStep));
if (nullptr == planarFigureGeometry)
{
return false;
}
auto abstractTransformGeometry = dynamic_cast(planarFigure->GetGeometry(timeStep));
if (nullptr != abstractTransformGeometry)
{
return false;
}
Point2D point2D;
// Get the point2D from the positionEvent
if (!this->TransformPositionEventToPoint2D(positionEvent, planarFigureGeometry, point2D))
{
return false;
}
// apply the controlPoint constraints of the planarFigure to get the
// coordinates that would actually be used.
const Point2D correctedPoint = const_cast(planarFigure)->ApplyControlPointConstraints(0, point2D);
// map the 2D coordinates of the new point to world-coordinates
// and transform those to display-coordinates
mitk::Point3D newPoint3D;
planarFigureGeometry->Map(correctedPoint, newPoint3D);
mitk::Point2D newDisplayPosition;
renderer->WorldToDisplay(newPoint3D, newDisplayPosition);
const int selectedControlPoint = planarFigure->GetSelectedControlPoint();
for (int i = 0; i < (int)planarFigure->GetNumberOfControlPoints(); ++i)
{
if (i != selectedControlPoint)
{
// Try to convert previous point to current display coordinates
mitk::Point3D previousPoint3D;
// map the 2D coordinates of the control-point to world-coordinates
planarFigureGeometry->Map(planarFigure->GetControlPoint(i), previousPoint3D);
if (renderer->GetCurrentWorldPlaneGeometry()->Distance(previousPoint3D) < 0.1) // ugly, but assert makes this work
{
mitk::Point2D previousDisplayPosition;
// transform the world-coordinates into display-coordinates
renderer->WorldToDisplay(previousPoint3D, previousDisplayPosition);
// Calculate the distance. We use display-coordinates here to make
// the check independent of the zoom-level of the rendering scene.
const double a = newDisplayPosition[0] - previousDisplayPosition[0];
const double b = newDisplayPosition[1] - previousDisplayPosition[1];
// If point is to close, do not set a new point
tooClose = (a * a + b * b < m_MinimumPointDistance);
}
if (tooClose)
return false; // abort loop early
}
}
return !tooClose; // default
}
void mitk::PlanarFigureInteractor::ConfigurationChanged()
{
const mitk::PropertyList::Pointer properties = GetAttributes();
std::string precision = "";
if (properties->GetStringProperty("precision", precision))
{
m_Precision = atof(precision.c_str());
}
else
{
m_Precision = (ScalarType)6.5;
}
std::string minPointDistance = "";
if (properties->GetStringProperty("minPointDistance", minPointDistance))
{
m_MinimumPointDistance = atof(minPointDistance.c_str());
}
else
{
m_MinimumPointDistance = (ScalarType)25.0;
}
}
diff --git a/Modules/QtPython/QmitkPythonVariableStackTableModel.cpp b/Modules/QtPython/QmitkPythonVariableStackTableModel.cpp
index 399903ff84..dfd18a0a43 100755
--- a/Modules/QtPython/QmitkPythonVariableStackTableModel.cpp
+++ b/Modules/QtPython/QmitkPythonVariableStackTableModel.cpp
@@ -1,221 +1,214 @@
/*============================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.
Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.
============================================================================*/
#include "QmitkPythonVariableStackTableModel.h"
#include
#include
#include
#include
#include
#include
#include "QmitkMimeTypes.h"
const QString QmitkPythonVariableStackTableModel::MITK_IMAGE_VAR_NAME = "mitkImage";
const QString QmitkPythonVariableStackTableModel::MITK_SURFACE_VAR_NAME = "mitkSurface";
QmitkPythonVariableStackTableModel::QmitkPythonVariableStackTableModel(QObject *parent)
:QAbstractTableModel(parent)
{
us::ModuleContext* context = us::GetModuleContext();
m_PythonServiceRef = context->GetServiceReference();
m_PythonService = context->GetService(m_PythonServiceRef);
m_PythonService->AddPythonCommandObserver( this );
}
QmitkPythonVariableStackTableModel::~QmitkPythonVariableStackTableModel()
{
us::ModuleContext* context = us::GetModuleContext();
context->UngetService( m_PythonServiceRef );
m_PythonService->RemovePythonCommandObserver( this );
}
bool QmitkPythonVariableStackTableModel::dropMimeData(const QMimeData * data, Qt::DropAction action, int, int, const QModelIndex &)
{
// Early exit, returning true, but not actually doing anything (ignoring data).
if (action == Qt::IgnoreAction)
return true;
// Note, we are returning true if we handled it, and false otherwise
bool returnValue = false;
if(data->hasFormat(QmitkMimeTypes::DataNodePtrs))
{
- MITK_DEBUG("QmitkPythonVariableStackTableModel") << "dropped MITK DataNode";
returnValue = true;
int i = 0;
QList dataNodeList = QmitkMimeTypes::ToDataNodePtrList(data);
mitk::DataNode* node = nullptr;
foreach(node, dataNodeList)
{
mitk::Image* mitkImage = dynamic_cast(node->GetData());
- MITK_DEBUG("QmitkPythonVariableStackTableModel") << "mitkImage is not null " << (mitkImage != nullptr? "true": "false");
QRegExp rx("^\\d");
QString varName(node->GetName().c_str());
// regex replace every character that is not allowed in a python variable
varName = varName.replace(QRegExp("[.\\+\\-*\\s\\/\\n\\t\\r]"),QString("_"));
if( mitkImage )
{
if ( varName.isEmpty() )
varName = MITK_IMAGE_VAR_NAME;
if ( rx.indexIn(varName) == 0)
varName.prepend("_").prepend(MITK_IMAGE_VAR_NAME);
if( i > 0 )
varName = QString("%1%2").arg(varName).arg(i);
- MITK_DEBUG("QmitkPythonVariableStackTableModel") << "varName" << varName.toStdString();
bool exportAsCvImage = mitkImage->GetDimension() == 2 && m_PythonService->IsOpenCvPythonWrappingAvailable();
if( exportAsCvImage )
{
int ret = QMessageBox::question(nullptr, "Export option",
"2D image detected. Export as OpenCV image to Python instead of an SimpleITK image?",
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
exportAsCvImage = ret == QMessageBox::Yes;
if(exportAsCvImage)
{
m_PythonService->CopyToPythonAsCvImage( mitkImage, varName.toStdString() );
++i;
}
}
if( !exportAsCvImage )
{
if( m_PythonService->IsSimpleItkPythonWrappingAvailable() )
{
m_PythonService->CopyToPythonAsSimpleItkImage( mitkImage, varName.toStdString() );
++i;
}
else
{
MITK_ERROR << "SimpleITK Python wrapping not available. Skipping export for image " << node->GetName();
}
}
}
else
{
mitk::Surface* surface = dynamic_cast(node->GetData());
- MITK_DEBUG("QmitkPythonVariableStackTableModel") << "found surface";
if( surface )
{
if (varName.isEmpty() )
varName = MITK_SURFACE_VAR_NAME;
if ( rx.indexIn(varName) == 0)
varName.prepend("_").prepend(MITK_SURFACE_VAR_NAME);
- MITK_DEBUG("QmitkPythonVariableStackTableModel") << "varName" << varName;
-
if( m_PythonService->IsVtkPythonWrappingAvailable() )
{
m_PythonService->CopyToPythonAsVtkPolyData( surface, varName.toStdString() );
}
else
{
MITK_ERROR << "VTK Python wrapping not available. Skipping export for surface " << node->GetName();
}
}
}
}
}
return returnValue;
}
QVariant QmitkPythonVariableStackTableModel::headerData(int section, Qt::Orientation orientation,
int role) const
{
QVariant headerData;
// show only horizontal header
if ( role == Qt::DisplayRole )
{
if( orientation == Qt::Horizontal )
{
// first column: "Attribute"
if(section == 0)
headerData = "Attribute";
else if(section == 1)
headerData = "Type";
else if(section == 2)
headerData = "Value";
}
}
return headerData;
}
Qt::ItemFlags QmitkPythonVariableStackTableModel::flags(const QModelIndex &index) const
{
Qt::ItemFlags flags = QAbstractItemModel::flags(index);
if(index.isValid())
return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | flags;
else
return Qt::ItemIsDropEnabled | flags;
}
int QmitkPythonVariableStackTableModel::rowCount(const QModelIndex &) const
{
return m_VariableStack.size();
}
int QmitkPythonVariableStackTableModel::columnCount(const QModelIndex &) const
{
return 3;
}
QVariant QmitkPythonVariableStackTableModel::data(const QModelIndex &index, int role) const
{
if (index.isValid() && !m_VariableStack.empty())
{
if(role == Qt::DisplayRole)
{
mitk::PythonVariable item = m_VariableStack.at(index.row());
if(index.column() == 0)
return QString::fromStdString(item.m_Name);
if(index.column() == 1)
return QString::fromStdString(item.m_Type);
if(index.column() == 2)
return QString::fromStdString(item.m_Value);
}
}
return QVariant();
}
QStringList QmitkPythonVariableStackTableModel::mimeTypes() const
{
return QAbstractTableModel::mimeTypes();
QStringList types;
types << "application/x-mitk-datanodes";
types << "application/x-qabstractitemmodeldatalist";
return types;
}
Qt::DropActions QmitkPythonVariableStackTableModel::supportedDropActions() const
{
return Qt::CopyAction | Qt::MoveAction;
}
-void QmitkPythonVariableStackTableModel::CommandExecuted(const std::string& pythonCommand)
+void QmitkPythonVariableStackTableModel::CommandExecuted(const std::string&)
{
- MITK_DEBUG("QmitkPythonVariableStackTableModel") << "command was executed " << pythonCommand;
m_VariableStack = m_PythonService->GetVariableStack();
QAbstractTableModel::beginResetModel();
QAbstractTableModel::endResetModel();
}
std::vector QmitkPythonVariableStackTableModel::GetVariableStack() const
{
return m_VariableStack;
}
diff --git a/Modules/QtWidgetsExt/include/QmitkTransferFunctionGeneratorWidget.h b/Modules/QtWidgetsExt/include/QmitkTransferFunctionGeneratorWidget.h
index 5bf7ea8d64..443f1b7cac 100644
--- a/Modules/QtWidgetsExt/include/QmitkTransferFunctionGeneratorWidget.h
+++ b/Modules/QtWidgetsExt/include/QmitkTransferFunctionGeneratorWidget.h
@@ -1,80 +1,80 @@
/*============================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.
Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.
============================================================================*/
#ifndef QMITKTRANSFERFUNCTIONGENERATORWIDGET_H
#define QMITKTRANSFERFUNCTIONGENERATORWIDGET_H
#include "MitkQtWidgetsExtExports.h"
#include "ui_QmitkTransferFunctionGeneratorWidget.h"
#include
#include
#include
#include
class MITKQTWIDGETSEXT_EXPORT QmitkTransferFunctionGeneratorWidget : public QWidget,
public Ui::QmitkTransferFunctionGeneratorWidget
{
Q_OBJECT
public:
QmitkTransferFunctionGeneratorWidget(QWidget *parent = nullptr, Qt::WindowFlags f = nullptr);
~QmitkTransferFunctionGeneratorWidget() override;
- void SetDataNode(mitk::DataNode *node);
+ void SetDataNode(mitk::DataNode *node, mitk::TimeStepType timestep = 0);
int AddPreset(const QString &presetName);
void SetPresetsTabEnabled(bool enable);
void SetThresholdTabEnabled(bool enable);
void SetBellTabEnabled(bool enable);
public slots:
void OnSavePreset();
void OnLoadPreset();
void OnDeltaLevelWindow(int dx, int dy);
void OnDeltaThreshold(int dx, int dy);
signals:
void SignalTransferFunctionModeChanged(int);
void SignalUpdateCanvas();
protected slots:
void OnPreset(int mode);
protected:
mitk::TransferFunctionProperty::Pointer tfpToChange;
double histoMinimum;
double histoMaximum;
double thPos;
double thDelta;
double deltaScale;
double deltaMax;
double deltaMin;
const mitk::Image::HistogramType *histoGramm;
QString presetFileName;
double ScaleDelta(int d) const;
};
#endif
diff --git a/Modules/QtWidgetsExt/include/QmitkTransferFunctionWidget.h b/Modules/QtWidgetsExt/include/QmitkTransferFunctionWidget.h
index d1d5a901d4..0ab5534657 100755
--- a/Modules/QtWidgetsExt/include/QmitkTransferFunctionWidget.h
+++ b/Modules/QtWidgetsExt/include/QmitkTransferFunctionWidget.h
@@ -1,79 +1,79 @@
/*============================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.
Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.
============================================================================*/
#ifndef QMITKTRANSFERFUNCTIONWIDGET_H
#define QMITKTRANSFERFUNCTIONWIDGET_H
#include "MitkQtWidgetsExtExports.h"
#include "ui_QmitkTransferFunctionWidget.h"
#include
#include
#include
#include
#include
#include
#include
namespace mitk
{
class BaseRenderer;
}
class MITKQTWIDGETSEXT_EXPORT QmitkTransferFunctionWidget : public QWidget, public Ui::QmitkTransferFunctionWidget
{
Q_OBJECT
public:
QmitkTransferFunctionWidget(QWidget *parent = nullptr, Qt::WindowFlags f = nullptr);
~QmitkTransferFunctionWidget() override;
- void SetDataNode(mitk::DataNode *node, const mitk::BaseRenderer *renderer = nullptr);
+ void SetDataNode(mitk::DataNode *node, mitk::TimeStepType timestep = 0, const mitk::BaseRenderer *renderer = nullptr);
void SetScalarLabel(const QString &scalarLabel);
void ShowScalarOpacityFunction(bool show);
void ShowColorFunction(bool show);
void ShowGradientOpacityFunction(bool show);
void SetScalarOpacityFunctionEnabled(bool enable);
void SetColorFunctionEnabled(bool enable);
void SetGradientOpacityFunctionEnabled(bool enable);
public slots:
void SetXValueScalar(const QString text);
void SetYValueScalar(const QString text);
void SetXValueGradient(const QString text);
void SetYValueGradient(const QString text);
void SetXValueColor(const QString text);
void OnUpdateCanvas();
void UpdateRanges();
void OnResetSlider();
void OnSpanChanged(int lower, int upper);
protected:
mitk::TransferFunctionProperty::Pointer tfpToChange;
int m_RangeSliderMin;
int m_RangeSliderMax;
mitk::SimpleHistogramCache histogramCache;
};
#endif
diff --git a/Modules/QtWidgetsExt/src/QmitkTransferFunctionGeneratorWidget.cpp b/Modules/QtWidgetsExt/src/QmitkTransferFunctionGeneratorWidget.cpp
index e244bb77a1..861c103b23 100644
--- a/Modules/QtWidgetsExt/src/QmitkTransferFunctionGeneratorWidget.cpp
+++ b/Modules/QtWidgetsExt/src/QmitkTransferFunctionGeneratorWidget.cpp
@@ -1,353 +1,367 @@
/*============================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.
Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.
============================================================================*/
#include "QmitkTransferFunctionGeneratorWidget.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
QmitkTransferFunctionGeneratorWidget::QmitkTransferFunctionGeneratorWidget(QWidget *parent, Qt::WindowFlags f)
: QWidget(parent, f), deltaScale(1.0), deltaMax(1024), deltaMin(1)
{
histoGramm = nullptr;
this->setupUi(this);
// LevelWindow Tab
{
connect(m_CrossLevelWindow, SIGNAL(SignalDeltaMove(int, int)), this, SLOT(OnDeltaLevelWindow(int, int)));
}
// Threshold Tab
{
connect(m_CrossThreshold, SIGNAL(SignalDeltaMove(int, int)), this, SLOT(OnDeltaThreshold(int, int)));
thDelta = 100;
}
// Presets Tab
{
m_TransferFunctionComboBox->setVisible(false);
connect(m_TransferFunctionComboBox, SIGNAL(activated(int)), this, SIGNAL(SignalTransferFunctionModeChanged(int)));
connect(m_TransferFunctionComboBox, SIGNAL(activated(int)), this, SLOT(OnPreset(int)));
connect(m_SavePreset, SIGNAL(clicked()), this, SLOT(OnSavePreset()));
connect(m_LoadPreset, SIGNAL(clicked()), this, SLOT(OnLoadPreset()));
}
presetFileName = ".";
}
int QmitkTransferFunctionGeneratorWidget::AddPreset(const QString &presetName)
{
m_TransferFunctionComboBox->setVisible(true);
m_TransferFunctionComboBox->addItem(presetName);
return m_TransferFunctionComboBox->count() - 1;
}
void QmitkTransferFunctionGeneratorWidget::SetPresetsTabEnabled(bool enable)
{
m_PresetTab->setEnabled(enable);
}
void QmitkTransferFunctionGeneratorWidget::SetThresholdTabEnabled(bool enable)
{
m_ThresholdTab->setEnabled(enable);
}
void QmitkTransferFunctionGeneratorWidget::SetBellTabEnabled(bool enable)
{
m_BellTab->setEnabled(enable);
}
void QmitkTransferFunctionGeneratorWidget::OnSavePreset()
{
if (tfpToChange.IsNull())
return;
mitk::TransferFunction::Pointer tf = tfpToChange->GetValue();
presetFileName = QFileDialog::getSaveFileName(
this, "Choose a filename to save the transfer function", presetFileName, "Transferfunction (*.xml)");
if (!presetFileName.endsWith(".xml"))
presetFileName.append(".xml");
MITK_INFO << "Saving Transferfunction under path: " << presetFileName.toStdString();
if (mitk::TransferFunctionPropertySerializer::SerializeTransferFunction(presetFileName.toLatin1(), tf))
{
QFontMetrics metrics(m_InfoPreset->font());
QString text = metrics.elidedText(presetFileName, Qt::ElideMiddle, m_InfoPreset->width());
m_InfoPreset->setText(QString("saved ") + text);
}
else
{
m_InfoPreset->setText(QString("saving failed"));
}
}
void QmitkTransferFunctionGeneratorWidget::OnLoadPreset()
{
if (tfpToChange.IsNull())
return;
presetFileName = QFileDialog::getOpenFileName(
this, "Choose a file to open the transfer function from", presetFileName, "Transferfunction (*.xml)");
MITK_INFO << "Loading Transferfunction from path: " << presetFileName.toStdString();
mitk::TransferFunction::Pointer tf =
mitk::TransferFunctionPropertySerializer::DeserializeTransferFunction(presetFileName.toLatin1());
if (tf.IsNotNull())
{
tfpToChange->SetValue(tf);
QFontMetrics metrics(m_InfoPreset->font());
QString text = metrics.elidedText(presetFileName, Qt::ElideMiddle, m_InfoPreset->width());
m_InfoPreset->setText(QString("loaded ") + text);
mitk::RenderingManager::GetInstance()->RequestUpdateAll();
emit SignalUpdateCanvas();
}
}
void QmitkTransferFunctionGeneratorWidget::OnPreset(int mode)
{
// first item is only information
if (--mode == -1)
return;
m_InfoPreset->setText(QString("selected ") + m_TransferFunctionComboBox->currentText());
// revert to first item
m_TransferFunctionComboBox->setCurrentIndex(0);
}
static double transformationGlocke(double x)
{
double z = 0.1;
double a = 2 - 2 * z;
double b = 2 * z - 1;
x = a * x + b;
return x;
}
static double stepFunctionGlocke(double x)
{
x = 1 - (2 * x - 1.0); // map [0.5;1] to [0,1]
x = x * (3 * x - 2 * x * x); // apply smoothing function
x = x * x;
return x;
}
double QmitkTransferFunctionGeneratorWidget::ScaleDelta(int d) const
{
return deltaScale * (double)d;
}
void QmitkTransferFunctionGeneratorWidget::OnDeltaLevelWindow(int dx, int dy) // bell
{
if (tfpToChange.IsNull())
return;
thPos += ScaleDelta(dx);
thDelta -= ScaleDelta(dy);
if (thDelta < deltaMin)
thDelta = deltaMin;
if (thDelta > deltaMax)
thDelta = deltaMax;
if (thPos < histoMinimum)
thPos = histoMinimum;
if (thPos > histoMaximum)
thPos = histoMaximum;
std::stringstream ss;
ss << "Click on the cross and move the mouse"
<< "\n"
<< "\n"
<< "center at " << thPos << "\n"
<< "width " << thDelta * 2;
m_InfoLevelWindow->setText(QString(ss.str().c_str()));
mitk::TransferFunction::Pointer tf = tfpToChange->GetValue();
// grayvalue->opacity
{
vtkPiecewiseFunction *f = tf->GetScalarOpacityFunction();
f->RemoveAllPoints();
for (int r = 0; r <= 6; r++)
{
double relPos = (r / 6.0) * 0.5 + 0.5;
f->AddPoint(thPos + thDelta * (-transformationGlocke(relPos)), stepFunctionGlocke(relPos));
f->AddPoint(thPos + thDelta * (transformationGlocke(relPos)), stepFunctionGlocke(relPos));
}
f->Modified();
}
// gradient at grayvalue->opacity
{
vtkPiecewiseFunction *f = tf->GetGradientOpacityFunction();
f->RemoveAllPoints();
f->AddPoint(0, 1.0);
f->Modified();
}
tf->Modified();
mitk::RenderingManager::GetInstance()->RequestUpdateAll();
emit SignalUpdateCanvas();
}
static double stepFunctionThreshold(double x)
{
x = 0.5 * x + 0.5; // map [-1;1] to [0,1]
x = x * (3 * x - 2 * x * x); // apply smoothing function
x = x * x;
return x;
}
void QmitkTransferFunctionGeneratorWidget::OnDeltaThreshold(int dx, int dy) // LEVELWINDOW
{
if (tfpToChange.IsNull())
return;
thPos += ScaleDelta(dx);
thDelta += ScaleDelta(dy);
if (thDelta < deltaMin)
thDelta = deltaMin;
if (thDelta > deltaMax)
thDelta = deltaMax;
if (thPos < histoMinimum)
thPos = histoMinimum;
if (thPos > histoMaximum)
thPos = histoMaximum;
std::stringstream ss;
ss << "Click on the cross and move the mouse"
<< "\n"
<< "\n"
<< "threshold at " << thPos << "\n"
<< "width " << thDelta * 2;
m_InfoThreshold->setText(QString(ss.str().c_str()));
mitk::TransferFunction::Pointer tf = tfpToChange->GetValue();
// grayvalue->opacity
{
vtkPiecewiseFunction *f = tf->GetScalarOpacityFunction();
f->RemoveAllPoints();
for (int r = 1; r <= 4; r++)
{
double relPos = r / 4.0;
f->AddPoint(thPos + thDelta * (-relPos), stepFunctionThreshold(-relPos));
f->AddPoint(thPos + thDelta * (relPos), stepFunctionThreshold(relPos));
}
f->Modified();
}
// gradient at grayvalue->opacity
{
vtkPiecewiseFunction *f = tf->GetGradientOpacityFunction();
f->RemoveAllPoints();
f->AddPoint(0, 1.0);
f->Modified();
}
tf->Modified();
mitk::RenderingManager::GetInstance()->RequestUpdateAll();
emit SignalUpdateCanvas();
}
QmitkTransferFunctionGeneratorWidget::~QmitkTransferFunctionGeneratorWidget()
{
}
-void QmitkTransferFunctionGeneratorWidget::SetDataNode(mitk::DataNode *node)
+void QmitkTransferFunctionGeneratorWidget::SetDataNode(mitk::DataNode *node, mitk::TimeStepType timestep)
{
histoGramm = nullptr;
if (node)
{
tfpToChange = dynamic_cast(node->GetProperty("TransferFunction"));
if (!tfpToChange)
node->SetProperty("TransferFunction", tfpToChange = mitk::TransferFunctionProperty::New());
mitk::TransferFunction::Pointer tf = tfpToChange->GetValue();
if (mitk::Image *image = dynamic_cast(node->GetData()))
{
- mitk::ImageStatisticsHolder *statistics = image->GetStatistics();
+ mitk::Image::Pointer inputImage = image;
+ if (image->GetTimeSteps() > 1)
+ {
+ if (!image->GetTimeGeometry()->IsValidTimeStep(timestep))
+ {
+ return;
+ }
+ mitk::ImageTimeSelector::Pointer timeselector = mitk::ImageTimeSelector::New();
+ timeselector->SetInput(image);
+ timeselector->SetTimeNr(timestep);
+ timeselector->UpdateLargestPossibleRegion();
+ inputImage = timeselector->GetOutput();
+ }
+
+ mitk::ImageStatisticsHolder *statistics = inputImage->GetStatistics();
histoMinimum = statistics->GetScalarValueMin();
histoMaximum = statistics->GetScalarValueMax();
}
else if (mitk::UnstructuredGrid *grid = dynamic_cast(node->GetData()))
{
double *range = grid->GetVtkUnstructuredGrid()->GetScalarRange();
histoMinimum = range[0];
histoMaximum = range[1];
double histoRange = histoMaximum - histoMinimum;
deltaMax = histoRange / 4.0;
deltaMin = histoRange / 400.0;
deltaScale = histoRange / 1024.0;
}
else
{
MITK_WARN << "QmitkTransferFunctonGeneratorWidget does not support " << node->GetData()->GetNameOfClass()
<< " instances";
}
thPos = (histoMinimum + histoMaximum) / 2.0;
}
else
{
tfpToChange = nullptr;
m_InfoPreset->setText(QString(""));
}
}
diff --git a/Modules/QtWidgetsExt/src/QmitkTransferFunctionWidget.cpp b/Modules/QtWidgetsExt/src/QmitkTransferFunctionWidget.cpp
index bde5c54854..2f5e727ba6 100755
--- a/Modules/QtWidgetsExt/src/QmitkTransferFunctionWidget.cpp
+++ b/Modules/QtWidgetsExt/src/QmitkTransferFunctionWidget.cpp
@@ -1,246 +1,263 @@
/*============================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.
Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.
============================================================================*/
#include "QmitkTransferFunctionWidget.h"
+#include "mitkImageTimeSelector.h"
#include
QmitkTransferFunctionWidget::QmitkTransferFunctionWidget(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f)
{
this->setupUi(this);
// signals and slots connections
connect(m_XEditScalarOpacity, SIGNAL(textEdited(const QString &)), this, SLOT(SetXValueScalar(const QString &)));
connect(m_YEditScalarOpacity, SIGNAL(textEdited(const QString &)), this, SLOT(SetYValueScalar(const QString &)));
connect(m_XEditGradientOpacity, SIGNAL(textEdited(const QString &)), this, SLOT(SetXValueGradient(const QString &)));
connect(m_YEditGradientOpacity, SIGNAL(textEdited(const QString &)), this, SLOT(SetYValueGradient(const QString &)));
connect(m_XEditColor, SIGNAL(textEdited(const QString &)), this, SLOT(SetXValueColor(const QString &)));
m_RangeSlider->setMinimum(-2048);
m_RangeSlider->setMaximum(2048);
connect(m_RangeSlider, SIGNAL(valuesChanged(int, int)), this, SLOT(OnSpanChanged(int, int)));
// reset button
connect(m_RangeSliderReset, SIGNAL(pressed()), this, SLOT(OnResetSlider()));
m_ScalarOpacityFunctionCanvas->SetQLineEdits(m_XEditScalarOpacity, m_YEditScalarOpacity);
m_GradientOpacityCanvas->SetQLineEdits(m_XEditGradientOpacity, m_YEditGradientOpacity);
m_ColorTransferFunctionCanvas->SetQLineEdits(m_XEditColor, nullptr);
m_ScalarOpacityFunctionCanvas->SetTitle("Grayvalue -> Opacity");
m_GradientOpacityCanvas->SetTitle("Grayvalue/Gradient -> Opacity");
m_ColorTransferFunctionCanvas->SetTitle("Grayvalue -> Color");
}
QmitkTransferFunctionWidget::~QmitkTransferFunctionWidget()
{
}
void QmitkTransferFunctionWidget::SetScalarLabel(const QString &scalarLabel)
{
m_textLabelX->setText(scalarLabel);
m_textLabelX_2->setText(scalarLabel);
m_textLabelX_3->setText(scalarLabel);
m_ScalarOpacityFunctionCanvas->SetTitle(scalarLabel + " -> Opacity");
m_GradientOpacityCanvas->SetTitle(scalarLabel + "/Gradient -> Opacity");
m_ColorTransferFunctionCanvas->SetTitle(scalarLabel + " -> Color");
}
void QmitkTransferFunctionWidget::ShowScalarOpacityFunction(bool show)
{
m_ScalarOpacityWidget->setVisible(show);
}
void QmitkTransferFunctionWidget::ShowColorFunction(bool show)
{
m_ColorWidget->setVisible(show);
}
void QmitkTransferFunctionWidget::ShowGradientOpacityFunction(bool show)
{
m_GradientOpacityWidget->setVisible(show);
}
void QmitkTransferFunctionWidget::SetScalarOpacityFunctionEnabled(bool enable)
{
m_ScalarOpacityWidget->setEnabled(enable);
}
void QmitkTransferFunctionWidget::SetColorFunctionEnabled(bool enable)
{
m_ColorWidget->setEnabled(enable);
}
void QmitkTransferFunctionWidget::SetGradientOpacityFunctionEnabled(bool enable)
{
m_GradientOpacityWidget->setEnabled(enable);
}
-void QmitkTransferFunctionWidget::SetDataNode(mitk::DataNode *node, const mitk::BaseRenderer *renderer)
+void QmitkTransferFunctionWidget::SetDataNode(mitk::DataNode *node, mitk::TimeStepType timestep, const mitk::BaseRenderer *renderer)
{
if (node)
{
tfpToChange = dynamic_cast(node->GetProperty("TransferFunction", renderer));
-
if (!tfpToChange)
{
if (!dynamic_cast(node->GetData()))
{
MITK_WARN << "QmitkTransferFunctionWidget::SetDataNode called with non-image node";
goto turnOff;
}
node->SetProperty("TransferFunction", tfpToChange = mitk::TransferFunctionProperty::New());
}
mitk::TransferFunction::Pointer tf = tfpToChange->GetValue();
- if (mitk::BaseData *data = node->GetData())
+ if (mitk::Image *data = dynamic_cast(node->GetData()))
{
- mitk::SimpleHistogram *h = histogramCache[data];
+ mitk::SimpleHistogram *h = nullptr;
+ if (data->GetTimeSteps() > 1)
+ {
+ if (!data->GetTimeGeometry()->IsValidTimeStep(timestep))
+ {
+ return;
+ }
+ mitk::ImageTimeSelector::Pointer timeselector = mitk::ImageTimeSelector::New();
+ timeselector->SetInput(data);
+ timeselector->SetTimeNr(timestep);
+ timeselector->UpdateLargestPossibleRegion();
+ auto inputImage = timeselector->GetOutput();
+ h = histogramCache[inputImage];
+ }
+ else
+ {
+ h = histogramCache[data];
+ }
m_RangeSliderMin = h->GetMin();
m_RangeSliderMax = h->GetMax();
m_RangeSlider->blockSignals(true);
m_RangeSlider->setMinimum(m_RangeSliderMin);
m_RangeSlider->setMaximum(m_RangeSliderMax);
m_RangeSlider->setMinimumValue(m_RangeSliderMin);
m_RangeSlider->setMaximumValue(m_RangeSliderMax);
m_RangeSlider->blockSignals(false);
m_ScalarOpacityFunctionCanvas->SetHistogram(h);
m_GradientOpacityCanvas->SetHistogram(h);
m_ColorTransferFunctionCanvas->SetHistogram(h);
}
OnUpdateCanvas();
return;
}
turnOff:
m_ScalarOpacityFunctionCanvas->setEnabled(false);
m_ScalarOpacityFunctionCanvas->SetHistogram(nullptr);
m_GradientOpacityCanvas->setEnabled(false);
m_GradientOpacityCanvas->SetHistogram(nullptr);
m_ColorTransferFunctionCanvas->setEnabled(false);
m_ColorTransferFunctionCanvas->SetHistogram(nullptr);
tfpToChange = nullptr;
}
void QmitkTransferFunctionWidget::OnUpdateCanvas()
{
if (tfpToChange.IsNull())
return;
mitk::TransferFunction::Pointer tf = tfpToChange->GetValue();
if (tf.IsNull())
return;
m_ScalarOpacityFunctionCanvas->SetPiecewiseFunction(tf->GetScalarOpacityFunction());
m_GradientOpacityCanvas->SetPiecewiseFunction(tf->GetGradientOpacityFunction());
m_ColorTransferFunctionCanvas->SetColorTransferFunction(tf->GetColorTransferFunction());
UpdateRanges();
m_ScalarOpacityFunctionCanvas->update();
m_GradientOpacityCanvas->update();
m_ColorTransferFunctionCanvas->update();
}
void QmitkTransferFunctionWidget::SetXValueScalar(const QString text)
{
if (!text.endsWith("."))
{
m_ScalarOpacityFunctionCanvas->SetX(text.toFloat());
mitk::RenderingManager::GetInstance()->RequestUpdateAll();
}
}
void QmitkTransferFunctionWidget::SetYValueScalar(const QString text)
{
if (!text.endsWith("."))
{
m_ScalarOpacityFunctionCanvas->SetY(text.toFloat());
mitk::RenderingManager::GetInstance()->RequestUpdateAll();
}
}
void QmitkTransferFunctionWidget::SetXValueGradient(const QString text)
{
if (!text.endsWith("."))
{
m_GradientOpacityCanvas->SetX(text.toFloat());
mitk::RenderingManager::GetInstance()->RequestUpdateAll();
}
}
void QmitkTransferFunctionWidget::SetYValueGradient(const QString text)
{
if (!text.endsWith("."))
{
m_GradientOpacityCanvas->SetY(text.toFloat());
mitk::RenderingManager::GetInstance()->RequestUpdateAll();
}
}
void QmitkTransferFunctionWidget::SetXValueColor(const QString text)
{
if (!text.endsWith("."))
{
m_ColorTransferFunctionCanvas->SetX(text.toFloat());
mitk::RenderingManager::GetInstance()->RequestUpdateAll();
}
}
void QmitkTransferFunctionWidget::UpdateRanges()
{
int lower = m_RangeSlider->minimumValue();
int upper = m_RangeSlider->maximumValue();
m_ScalarOpacityFunctionCanvas->SetMin(lower);
m_ScalarOpacityFunctionCanvas->SetMax(upper);
m_GradientOpacityCanvas->SetMin(lower);
m_GradientOpacityCanvas->SetMax(upper);
m_ColorTransferFunctionCanvas->SetMin(lower);
m_ColorTransferFunctionCanvas->SetMax(upper);
}
void QmitkTransferFunctionWidget::OnSpanChanged(int, int)
{
UpdateRanges();
m_GradientOpacityCanvas->update();
m_ColorTransferFunctionCanvas->update();
m_ScalarOpacityFunctionCanvas->update();
}
void QmitkTransferFunctionWidget::OnResetSlider()
{
m_RangeSlider->blockSignals(true);
m_RangeSlider->setMaximumValue(m_RangeSliderMax);
m_RangeSlider->setMinimumValue(m_RangeSliderMin);
m_RangeSlider->blockSignals(false);
UpdateRanges();
m_GradientOpacityCanvas->update();
m_ColorTransferFunctionCanvas->update();
m_ScalarOpacityFunctionCanvas->update();
}
diff --git a/Modules/SceneSerializationBase/include/mitkVectorPropertySerializer.h b/Modules/SceneSerializationBase/include/mitkVectorPropertySerializer.h
index a2710f1d7b..19eca9289d 100644
--- a/Modules/SceneSerializationBase/include/mitkVectorPropertySerializer.h
+++ b/Modules/SceneSerializationBase/include/mitkVectorPropertySerializer.h
@@ -1,153 +1,151 @@
/*============================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.
Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.
============================================================================*/
#ifndef mitkVectorPropertySerializer_h
#define mitkVectorPropertySerializer_h
#include "mitkBasePropertySerializer.h"
#include "mitkVectorProperty.h"
#include
#include
namespace mitk
{
/**
\brief Serializes a VectorProperty
Serializes an instance of VectorProperty into a XML structure like
\verbatim
\endverbatim
This class is implemented as a template and makes use of std::stringstream
for necessary conversions of specific data types to and from string.
For numeric types, the class adds a precision token to stringstream that
should usually suffice.
*/
template
class MITKSCENESERIALIZATIONBASE_EXPORT VectorPropertySerializer : public BasePropertySerializer
{
public:
// Expand manually most of mitkClassMacro:
// mitkClassMacro(VectorProperty, mitk::BaseProperty);
// This manual expansion is done to override explicitely
// the GetNameOfClass methods
typedef VectorProperty PropertyType;
typedef VectorPropertySerializer Self;
typedef BasePropertySerializer SuperClass;
typedef itk::SmartPointer Pointer;
typedef itk::SmartPointer ConstPointer;
std::vector GetClassHierarchy() const override { return mitk::GetClassHierarchy(); }
// This function must return different
// strings in function of the template parameter!
// Serialization depends on this feature.
static const char *GetStaticNameOfClass()
{
// concatenate a prefix dependent on the template type and our own classname
static std::string nameOfClass =
std::string(VectorPropertyDataType::prefix()) + "VectorPropertySerializer";
return nameOfClass.c_str();
}
const char *GetNameOfClass() const override { return this->GetStaticNameOfClass(); }
itkFactorylessNewMacro(Self);
itkCloneMacro(Self);
//! Build an XML version of this property
tinyxml2::XMLElement* Serialize(tinyxml2::XMLDocument& doc) override
{
auto *listElement = doc.NewElement("Values");
if (const PropertyType *prop = dynamic_cast(m_Property.GetPointer()))
{
typename PropertyType::VectorType elements = prop->GetValue();
unsigned int index(0);
for (auto listEntry : elements)
{
std::stringstream indexS;
indexS << index++;
auto *entryElement = doc.NewElement("Value");
entryElement->SetAttribute("idx", indexS.str().c_str());
entryElement->SetAttribute("value", boost::lexical_cast(listEntry).c_str());
listElement->InsertEndChild(entryElement);
}
return listElement;
}
else
{
return nullptr;
}
}
//! Construct a property from an XML serialization
BaseProperty::Pointer Deserialize(const tinyxml2::XMLElement *listElement) override
{
typename PropertyType::VectorType datalist;
if (listElement)
{
- MITK_DEBUG << "Deserializing " << *listElement;
-
unsigned int index(0);
std::string valueString;
DATATYPE value;
for (auto *valueElement = listElement->FirstChildElement("Value"); valueElement;
valueElement = valueElement->NextSiblingElement("Value"))
{
valueString = valueElement->Attribute("value");
if (valueString.empty())
{
MITK_ERROR << "Missing value attribute in list";
return nullptr;
}
try
{
value = boost::lexical_cast(valueString);
}
catch (boost::bad_lexical_cast &e)
{
MITK_ERROR << "Could not parse '" << valueString << "' as number: " << e.what();
return nullptr;
}
datalist.push_back(value);
++index;
}
typename PropertyType::Pointer property = PropertyType::New();
property->SetValue(datalist);
return property.GetPointer();
}
else
{
MITK_ERROR << "Missing tag.";
}
return nullptr;
}
};
typedef VectorPropertySerializer DoubleVectorPropertySerializer;
typedef VectorPropertySerializer IntVectorPropertySerializer;
} // namespace
#endif
diff --git a/Modules/Segmentation/Interactions/mitkAutoMLSegmentationWithPreviewTool.cpp b/Modules/Segmentation/Interactions/mitkAutoMLSegmentationWithPreviewTool.cpp
index 63c827db0c..881f688fc3 100644
--- a/Modules/Segmentation/Interactions/mitkAutoMLSegmentationWithPreviewTool.cpp
+++ b/Modules/Segmentation/Interactions/mitkAutoMLSegmentationWithPreviewTool.cpp
@@ -1,205 +1,209 @@
/*============================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.
Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.
============================================================================*/
// MITK
#include "mitkAutoMLSegmentationWithPreviewTool.h"
#include "mitkImageAccessByItk.h"
#include "mitkToolManager.h"
#include
#include
#include
#include
#include
#include
#include
// ITK
#include
#include
mitk::AutoMLSegmentationWithPreviewTool::AutoMLSegmentationWithPreviewTool() : AutoSegmentationWithPreviewTool(true)
{
}
void mitk::AutoMLSegmentationWithPreviewTool::SetSelectedLabels(const SelectedLabelVectorType& regions)
{
if (m_SelectedLabels != regions)
{
m_SelectedLabels = regions;
//Note: we do not call this->Modified() on puprose. Reason: changing the
//selected regions should not force to run otsu filter in DoUpdatePreview due to changed MTime.
}
}
const mitk::LabelSetImage* mitk::AutoMLSegmentationWithPreviewTool::GetMLPreview() const
{
if (m_MLPreviewNode.IsNotNull())
{
const auto mlPreviewImage = dynamic_cast(this->m_MLPreviewNode->GetData());
return mlPreviewImage;
}
return nullptr;
}
mitk::AutoMLSegmentationWithPreviewTool::SelectedLabelVectorType mitk::AutoMLSegmentationWithPreviewTool::GetSelectedLabels() const
{
return this->m_SelectedLabels;
}
void mitk::AutoMLSegmentationWithPreviewTool::Activated()
{
Superclass::Activated();
m_SelectedLabels = {};
m_MLPreviewNode = mitk::DataNode::New();
m_MLPreviewNode->SetProperty("name", StringProperty::New(std::string(this->GetName()) + "ML preview"));
m_MLPreviewNode->SetProperty("helper object", BoolProperty::New(true));
m_MLPreviewNode->SetVisibility(true);
m_MLPreviewNode->SetOpacity(1.0);
this->GetToolManager()->GetDataStorage()->Add(m_MLPreviewNode);
}
void mitk::AutoMLSegmentationWithPreviewTool::Deactivated()
{
this->GetToolManager()->GetDataStorage()->Remove(m_MLPreviewNode);
m_MLPreviewNode = nullptr;
Superclass::Deactivated();
}
void mitk::AutoMLSegmentationWithPreviewTool::UpdateCleanUp()
{
if (m_MLPreviewNode.IsNotNull())
m_MLPreviewNode->SetVisibility(m_SelectedLabels.empty());
if (nullptr != this->GetPreviewSegmentationNode())
this->GetPreviewSegmentationNode()->SetVisibility(!m_SelectedLabels.empty());
if (m_SelectedLabels.empty())
{
this->ResetPreviewNode();
}
}
-void mitk::AutoMLSegmentationWithPreviewTool::DoUpdatePreview(const Image* inputAtTimeStep, const Image* /*oldSegAtTimeStep*/, Image* previewImage, TimeStepType timeStep)
+void mitk::AutoMLSegmentationWithPreviewTool::SetNodeProperties(LabelSetImage::Pointer newMLPreview)
{
- const auto timePoint = mitk::RenderingManager::GetInstance()->GetTimeNavigationController()->GetSelectedTimePoint();
-
- if (nullptr == m_MLPreviewNode->GetData()
- || this->GetMTime() > m_MLPreviewNode->GetData()->GetMTime()
- || this->m_LastMLTimeStep != timeStep //this covers the case where dynamic
- //segmentations have to compute a preview
- //for all time steps on confirmation
- || this->GetLastTimePointOfUpdate() != timePoint //this ensures that static seg
- //previews work with dynamic images
- //with avoiding unnecessary other computations
- )
- {
- if (nullptr == inputAtTimeStep)
- {
- MITK_WARN << "Cannot run segementation. Currently selected input image is not set.";
- return;
- }
-
- this->m_LastMLTimeStep = timeStep;
-
- auto newMLPreview = ComputeMLPreview(inputAtTimeStep, timeStep);
-
- if (newMLPreview.IsNotNull())
+ if (newMLPreview.IsNotNull())
{
this->m_MLPreviewNode->SetData(newMLPreview);
this->m_MLPreviewNode->SetProperty("binary", mitk::BoolProperty::New(false));
mitk::RenderingModeProperty::Pointer renderingMode = mitk::RenderingModeProperty::New();
renderingMode->SetValue(mitk::RenderingModeProperty::LOOKUPTABLE_LEVELWINDOW_COLOR);
this->m_MLPreviewNode->SetProperty("Image Rendering.Mode", renderingMode);
mitk::LookupTable::Pointer lut = mitk::LookupTable::New();
mitk::LookupTableProperty::Pointer prop = mitk::LookupTableProperty::New(lut);
vtkSmartPointer lookupTable = vtkSmartPointer::New();
lookupTable->SetHueRange(1.0, 0.0);
lookupTable->SetSaturationRange(1.0, 1.0);
lookupTable->SetValueRange(1.0, 1.0);
lookupTable->SetTableRange(-1.0, 1.0);
lookupTable->Build();
lut->SetVtkLookupTable(lookupTable);
prop->SetLookupTable(lut);
this->m_MLPreviewNode->SetProperty("LookupTable", prop);
mitk::LevelWindowProperty::Pointer levWinProp = mitk::LevelWindowProperty::New();
mitk::LevelWindow levelwindow;
levelwindow.SetRangeMinMax(0, newMLPreview->GetStatistics()->GetScalarValueMax());
levWinProp->SetLevelWindow(levelwindow);
this->m_MLPreviewNode->SetProperty("levelwindow", levWinProp);
}
+}
+
+void mitk::AutoMLSegmentationWithPreviewTool::DoUpdatePreview(const Image* inputAtTimeStep, const Image* /*oldSegAtTimeStep*/, Image* previewImage, TimeStepType timeStep)
+{
+ const auto timePoint = mitk::RenderingManager::GetInstance()->GetTimeNavigationController()->GetSelectedTimePoint();
+
+ if (nullptr == m_MLPreviewNode->GetData()
+ || this->GetMTime() > m_MLPreviewNode->GetData()->GetMTime()
+ || this->m_LastMLTimeStep != timeStep //this covers the case where dynamic
+ //segmentations have to compute a preview
+ //for all time steps on confirmation
+ || this->GetLastTimePointOfUpdate() != timePoint //this ensures that static seg
+ //previews work with dynamic images
+ //with avoiding unnecessary other computations
+ )
+ {
+ if (nullptr == inputAtTimeStep)
+ {
+ MITK_WARN << "Cannot run segementation. Currently selected input image is not set.";
+ return;
+ }
+
+ this->m_LastMLTimeStep = timeStep;
+
+ auto newMLPreview = ComputeMLPreview(inputAtTimeStep, timeStep);
+ this->SetNodeProperties(newMLPreview);
}
if (!m_SelectedLabels.empty())
{
const auto mlPreviewImage = this->GetMLPreview();
if (nullptr != mlPreviewImage)
{
AccessByItk_n(mlPreviewImage, CalculateMergedSimplePreview, (previewImage, timeStep));
}
}
}
template
void mitk::AutoMLSegmentationWithPreviewTool::CalculateMergedSimplePreview(const itk::Image* itkImage, mitk::Image* segmentation, unsigned int timeStep)
{
typedef itk::Image InputImageType;
typedef itk::Image OutputImageType;
typedef itk::BinaryThresholdImageFilter FilterType;
typename FilterType::Pointer filter = FilterType::New();
// InputImageType::Pointer itkImage;
typename OutputImageType::Pointer itkBinaryResultImage;
filter->SetInput(itkImage);
filter->SetLowerThreshold(m_SelectedLabels[0]);
filter->SetUpperThreshold(m_SelectedLabels[0]);
filter->SetInsideValue(1);
filter->SetOutsideValue(0);
filter->AddObserver(itk::ProgressEvent(), m_ProgressCommand);
filter->Update();
itkBinaryResultImage = filter->GetOutput();
itkBinaryResultImage->DisconnectPipeline();
// if more than one region id is used compute the union of all given binary regions
for (const auto labelID : m_SelectedLabels)
{
if (labelID != m_SelectedLabels[0])
{
filter->SetLowerThreshold(labelID);
filter->SetUpperThreshold(labelID);
filter->SetInsideValue(1);
filter->SetOutsideValue(0);
filter->Update();
typename OutputImageType::Pointer tempImage = filter->GetOutput();
typename itk::OrImageFilter::Pointer orFilter =
itk::OrImageFilter::New();
orFilter->SetInput1(tempImage);
orFilter->SetInput2(itkBinaryResultImage);
orFilter->AddObserver(itk::ProgressEvent(), m_ProgressCommand);
orFilter->UpdateLargestPossibleRegion();
itkBinaryResultImage = orFilter->GetOutput();
}
}
//----------------------------------------------------------------------------------------------------
segmentation->SetVolume((void*)(itkBinaryResultImage->GetPixelContainer()->GetBufferPointer()), timeStep);
}
diff --git a/Modules/Segmentation/Interactions/mitkAutoMLSegmentationWithPreviewTool.h b/Modules/Segmentation/Interactions/mitkAutoMLSegmentationWithPreviewTool.h
index 878fd5592c..60921765c6 100644
--- a/Modules/Segmentation/Interactions/mitkAutoMLSegmentationWithPreviewTool.h
+++ b/Modules/Segmentation/Interactions/mitkAutoMLSegmentationWithPreviewTool.h
@@ -1,82 +1,82 @@
/*============================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.
Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.
============================================================================*/
#ifndef MITK_AUTO_ML_SEGMENTATION_WITH_PREVIEW_TOOL_H
#define MITK_AUTO_ML_SEGMENTATION_WITH_PREVIEW_TOOL_H
#include "mitkAutoSegmentationWithPreviewTool.h"
#include "mitkDataNode.h"
#include "mitkLabelSetImage.h"
#include
namespace mitk
{
/**
\brief Base class for any auto segmentation tool that provides a preview of the new segmentation and generates
segmentations with multiple labels.
This tool class implements the basic logic to handle previews of multi label segmentations and
to allow to pick arbitrary labels as selected and merge them to a single segmentation to store this
segmentation as confirmed segmentation.
\ingroup ToolManagerEtAl
\sa mitk::Tool
\sa QmitkInteractiveSegmentation
*/
class MITKSEGMENTATION_EXPORT AutoMLSegmentationWithPreviewTool : public AutoSegmentationWithPreviewTool
{
public:
mitkClassMacro(AutoMLSegmentationWithPreviewTool, AutoSegmentationWithPreviewTool);
void Activated() override;
void Deactivated() override;
using SelectedLabelVectorType = std::vector;
void SetSelectedLabels(const SelectedLabelVectorType& regions);
SelectedLabelVectorType GetSelectedLabels() const;
const LabelSetImage* GetMLPreview() const;
protected:
AutoMLSegmentationWithPreviewTool();
~AutoMLSegmentationWithPreviewTool() = default;
void UpdateCleanUp() override;
void DoUpdatePreview(const Image* inputAtTimeStep, const Image* oldSegAtTimeStep, Image* previewImage, TimeStepType timeStep) override;
-
+ virtual void SetNodeProperties(LabelSetImage::Pointer);
/** Function to generate the new multi lable preview for a given time step input image.
* The function must be implemented by derived tools.
* This function is called by DoUpdatePreview if needed.
* Reasons are:
* - ML preview does not exist
* - Modify time of tools is newer then of ML preview
* - ML preview was not generated for the current selected timestep of input image or for the current selected timepoint.*/
virtual LabelSetImage::Pointer ComputeMLPreview(const Image* inputAtTimeStep, TimeStepType timeStep) = 0;
private:
/** Function to generate a simple (single lable) preview by merging all labels of the ML preview that are selected and
* copies that single label preview to the passed previewImage.
* This function is called by DoUpdatePreview if needed.
* @param mlPreviewImage Multi label preview that is the source.
* @param previewImage Pointer to the single label preview image that should receive the merged selected labels.
* @timeStep Time step of the previewImage that should be filled.*/
template
void CalculateMergedSimplePreview(const itk::Image* mlImage, mitk::Image* segmentation, unsigned int timeStep);
SelectedLabelVectorType m_SelectedLabels = {};
// holds the multilabel result as a preview image
mitk::DataNode::Pointer m_MLPreviewNode;
TimeStepType m_LastMLTimeStep = 0;
};
}
#endif
diff --git a/Modules/Segmentation/Interactions/mitkProcessExecutor.cpp b/Modules/Segmentation/Interactions/mitkProcessExecutor.cpp
new file mode 100644
index 0000000000..d65969bb8a
--- /dev/null
+++ b/Modules/Segmentation/Interactions/mitkProcessExecutor.cpp
@@ -0,0 +1,153 @@
+/*============================================================================
+
+The Medical Imaging Interaction Toolkit (MITK)
+
+Copyright (c) German Cancer Research Center (DKFZ)
+All rights reserved.
+
+Use of this source code is governed by a 3-clause BSD license that can be
+found in the LICENSE file.
+
+============================================================================*/
+
+#include "mitkProcessExecutor.h"
+
+#include
+#include
+#include
+#include
+
+namespace mitk
+{
+ std::string ProcessExecutor::GetOSDependendExecutableName(const std::string &name)
+ {
+#if defined(_WIN32)
+
+ if (itksys::SystemTools::GetFilenameLastExtension(name).empty())
+ {
+ return name + ".exe";
+ }
+
+ return name;
+
+#else
+ auto result = itksys::SystemTools::GetFilenamePath(name);
+ if (EnsureCorrectOSPathSeparator(result).empty())
+ {
+ return "./" + name;
+ }
+ else
+ {
+ return name;
+ }
+
+#endif
+ }
+
+ std::string ProcessExecutor::EnsureCorrectOSPathSeparator(const std::string &path)
+ {
+ std::string ret = path;
+
+#ifdef _WIN32
+ const std::string curSep = "\\";
+ const char wrongSep = '/';
+#else
+ const std::string curSep = "/";
+ const char wrongSep = '\\';
+#endif
+
+ std::string::size_type pos = ret.find_first_of(wrongSep);
+
+ while (pos != std::string::npos)
+ {
+ ret.replace(pos, 1, curSep);
+
+ pos = ret.find_first_of(wrongSep);
+ }
+
+ return ret;
+ }
+
+ int ProcessExecutor::GetExitValue() { return this->m_ExitValue; };
+
+ bool ProcessExecutor::Execute(const std::string &executionPath, const ArgumentListType &argumentList)
+ {
+ std::vector pArguments_(argumentList.size() + 1);
+
+ for (ArgumentListType::size_type index = 0; index < argumentList.size(); ++index)
+ {
+ pArguments_[index] = argumentList[index].c_str();
+ }
+ pArguments_.push_back(nullptr); //terminating null element as required by ITK
+
+ bool normalExit = false;
+
+ try
+ {
+ itksysProcess *processID = itksysProcess_New();
+ itksysProcess_SetCommand(processID, pArguments_.data());
+
+ itksysProcess_SetWorkingDirectory(processID, executionPath.c_str());
+
+ if (this->m_SharedOutputPipes)
+ {
+ itksysProcess_SetPipeShared(processID, itksysProcess_Pipe_STDOUT, 1);
+ itksysProcess_SetPipeShared(processID, itksysProcess_Pipe_STDERR, 1);
+ }
+
+ itksysProcess_Execute(processID);
+
+ char *rawOutput = nullptr;
+ int outputLength = 0;
+ while (true)
+ {
+ int dataStatus = itksysProcess_WaitForData(processID, &rawOutput, &outputLength, nullptr);
+
+ if (dataStatus == itksysProcess_Pipe_STDOUT)
+ {
+ std::string data(rawOutput, outputLength);
+ this->InvokeEvent(ExternalProcessStdOutEvent(data));
+ }
+ else if (dataStatus == itksysProcess_Pipe_STDERR)
+ {
+ std::string data(rawOutput, outputLength);
+ this->InvokeEvent(ExternalProcessStdErrEvent(data));
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ itksysProcess_WaitForExit(processID, nullptr);
+
+ auto state = static_cast(itksysProcess_GetState(processID));
+
+ normalExit = (state == itksysProcess_State_Exited);
+ this->m_ExitValue = itksysProcess_GetExitValue(processID);
+ }
+ catch (...)
+ {
+ throw;
+ }
+ return normalExit;
+ };
+
+ bool ProcessExecutor::Execute(const std::string &executionPath,
+ const std::string &executableName,
+ ArgumentListType argumentList)
+ {
+ std::string executableName_OS = GetOSDependendExecutableName(executableName);
+ argumentList.insert(argumentList.begin(), executableName_OS);
+
+ return Execute(executionPath, argumentList);
+ }
+
+ ProcessExecutor::ProcessExecutor()
+ {
+ this->m_ExitValue = 0;
+ this->m_SharedOutputPipes = false;
+ }
+
+ ProcessExecutor::~ProcessExecutor() = default;
+} // namespace mitk
diff --git a/Modules/Segmentation/Interactions/mitkProcessExecutor.h b/Modules/Segmentation/Interactions/mitkProcessExecutor.h
new file mode 100644
index 0000000000..79856889b4
--- /dev/null
+++ b/Modules/Segmentation/Interactions/mitkProcessExecutor.h
@@ -0,0 +1,110 @@
+/*============================================================================
+
+The Medical Imaging Interaction Toolkit (MITK)
+
+Copyright (c) German Cancer Research Center (DKFZ)
+All rights reserved.
+
+Use of this source code is governed by a 3-clause BSD license that can be
+found in the LICENSE file.
+
+============================================================================*/
+
+// Class is adapted from MatchPoint ProcessExecutor
+
+#ifndef __MITK_PROCESS_EXECUTOR_H
+#define __MITK_PROCESS_EXECUTOR_H
+
+#include
+#include
+#include
+
+namespace mitk
+{
+ class ExternalProcessOutputEvent : public itk::AnyEvent
+ {
+ public:
+ typedef ExternalProcessOutputEvent Self;
+ typedef itk::AnyEvent Superclass;
+
+ explicit ExternalProcessOutputEvent(const std::string &output = "") : m_Output(output) {}
+ ~ExternalProcessOutputEvent() override {}
+
+ const char *GetEventName() const override { return "ExternalProcessOutputEvent"; }
+ bool CheckEvent(const ::itk::EventObject *e) const override { return dynamic_cast(e); }
+ itk::EventObject *MakeObject() const override { return new Self(m_Output); }
+ std::string GetOutput() const { return m_Output; }
+
+ private:
+ std::string m_Output;
+ };
+
+#define mitkProcessExecutorEventMacro(classname) \
+ class classname : public ExternalProcessOutputEvent \
+ { \
+ public: \
+ typedef classname Self; \
+ typedef ExternalProcessOutputEvent Superclass; \
+ \
+ explicit classname(const std::string &output) : Superclass(output) {} \
+ ~classname() override {} \
+ \
+ virtual const char *GetEventName() const { return #classname; } \
+ virtual bool CheckEvent(const ::itk::EventObject *e) const { return dynamic_cast(e); } \
+ virtual ::itk::EventObject *MakeObject() const { return new Self(this->GetOutput()); } \
+ };
+
+ mitkProcessExecutorEventMacro(ExternalProcessStdOutEvent);
+ mitkProcessExecutorEventMacro(ExternalProcessStdErrEvent);
+
+ /**
+ * @brief You may register an observer for an ExternalProcessOutputEvent, ExternalProcessStdOutEvent or
+ * ExternalProcessStdErrEvent in order to get notified of any output.
+ * @remark The events will only be invoked if the pipes are NOT(!) shared. By default the pipes are not shared.
+ *
+ */
+ class MITKSEGMENTATION_EXPORT ProcessExecutor : public itk::Object
+ {
+ public:
+ using Self = ProcessExecutor;
+ using Superclass = ::itk::Object;
+ using Pointer = ::itk::SmartPointer;
+ using ConstPointer = ::itk::SmartPointer;
+
+ itkTypeMacro(ProcessExecutor, ::itk::Object);
+ itkFactorylessNewMacro(Self);
+
+ itkSetMacro(SharedOutputPipes, bool);
+ itkGetConstMacro(SharedOutputPipes, bool);
+
+ using ArgumentListType = std::vector;
+
+ bool Execute(const std::string &executionPath, const std::string &executableName, ArgumentListType argumentList);
+
+ /**
+ * @brief Executes the process. This version assumes that the executable name is the first argument in the argument
+ * list and has already been converted to its OS dependent name via the static convert function of this class.
+ */
+ bool Execute(const std::string &executionPath, const ArgumentListType &argumentList);
+
+ int GetExitValue();
+ static std::string EnsureCorrectOSPathSeparator(const std::string &);
+
+ static std::string GetOSDependendExecutableName(const std::string &name);
+
+ protected:
+ ProcessExecutor();
+ ~ProcessExecutor() override;
+
+ int m_ExitValue;
+
+ /**
+ * @brief Specifies if the child process should share the output pipes (true) or not (false).
+ * If pipes are not shared the output will be passed by invoking ExternalProcessOutputEvents
+ * @remark The events will only be invoked if the pipes are NOT(!) shared.
+ */
+ bool m_SharedOutputPipes;
+ };
+
+} // namespace mitk
+#endif
diff --git a/Modules/Segmentation/Interactions/mitknnUnetTool.cpp b/Modules/Segmentation/Interactions/mitknnUnetTool.cpp
new file mode 100644
index 0000000000..c2db0bcca3
--- /dev/null
+++ b/Modules/Segmentation/Interactions/mitknnUnetTool.cpp
@@ -0,0 +1,322 @@
+/*============================================================================
+
+The Medical Imaging Interaction Toolkit (MITK)
+
+Copyright (c) German Cancer Research Center (DKFZ)
+All rights reserved.
+
+Use of this source code is governed by a 3-clause BSD license that can be
+found in the LICENSE file.
+
+============================================================================*/
+
+#include "mitknnUnetTool.h"
+
+#include "mitkIOUtil.h"
+#include "mitkProcessExecutor.h"
+#include
+#include
+#include
+#include
+#include
+
+namespace mitk
+{
+ MITK_TOOL_MACRO(MITKSEGMENTATION_EXPORT, nnUNetTool, "nnUNet tool");
+}
+
+mitk::nnUNetTool::nnUNetTool()
+{
+ this->SetMitkTempDir(IOUtil::CreateTemporaryDirectory("mitk-XXXXXX"));
+}
+
+mitk::nnUNetTool::~nnUNetTool()
+{
+ itksys::SystemTools::RemoveADirectory(this->GetMitkTempDir());
+}
+
+void mitk::nnUNetTool::Activated()
+{
+ Superclass::Activated();
+ m_InputOutputPair = std::make_pair(nullptr, nullptr);
+}
+
+void mitk::nnUNetTool::UpdateCleanUp()
+{
+ // This overriden method is intentionally left out for setting later upon demand
+ // in the `RenderOutputBuffer` method.
+}
+
+void mitk::nnUNetTool::RenderOutputBuffer()
+{
+ if (this->m_OutputBuffer != nullptr)
+ {
+ Superclass::SetNodeProperties(this->m_OutputBuffer);
+ this->ClearOutputBuffer();
+ try
+ {
+ if (nullptr != this->GetPreviewSegmentationNode())
+ {
+ this->GetPreviewSegmentationNode()->SetVisibility(!this->GetSelectedLabels().empty());
+ }
+ if (this->GetSelectedLabels().empty())
+ {
+ this->ResetPreviewNode();
+ }
+ }
+ catch (const mitk::Exception &e)
+ {
+ MITK_INFO << e.GetDescription();
+ }
+ }
+}
+
+void mitk::nnUNetTool::SetNodeProperties(LabelSetImage::Pointer segmentation)
+{
+ // This overriden method doesn't set node properties. Intentionally left out for setting later upon demand
+ // in the `RenderOutputBuffer` method.
+ this->m_OutputBuffer = segmentation;
+}
+
+mitk::LabelSetImage::Pointer mitk::nnUNetTool::GetOutputBuffer()
+{
+ return this->m_OutputBuffer;
+}
+
+void mitk::nnUNetTool::ClearOutputBuffer()
+{
+ this->m_OutputBuffer = nullptr;
+}
+
+us::ModuleResource mitk::nnUNetTool::GetIconResource() const
+{
+ us::Module *module = us::GetModuleContext()->GetModule();
+ us::ModuleResource resource = module->GetResource("Watershed_48x48.png");
+ return resource;
+}
+
+const char **mitk::nnUNetTool::GetXPM() const
+{
+ return nullptr;
+}
+
+const char *mitk::nnUNetTool::GetName() const
+{
+ return "nnUNet";
+}
+
+mitk::DataStorage *mitk::nnUNetTool::GetDataStorage()
+{
+ return this->GetToolManager()->GetDataStorage();
+}
+
+mitk::DataNode *mitk::nnUNetTool::GetRefNode()
+{
+ return this->GetToolManager()->GetReferenceData(0);
+}
+
+namespace
+{
+ void onPythonProcessEvent(itk::Object * /*pCaller*/, const itk::EventObject &e, void *)
+ {
+ std::string testCOUT;
+ std::string testCERR;
+ const auto *pEvent = dynamic_cast(&e);
+
+ if (pEvent)
+ {
+ testCOUT = testCOUT + pEvent->GetOutput();
+ MITK_INFO << testCOUT;
+ }
+
+ const auto *pErrEvent = dynamic_cast(&e);
+
+ if (pErrEvent)
+ {
+ testCERR = testCERR + pErrEvent->GetOutput();
+ MITK_ERROR << testCERR;
+ }
+ }
+} // namespace
+
+mitk::LabelSetImage::Pointer mitk::nnUNetTool::ComputeMLPreview(const Image *inputAtTimeStep, TimeStepType /*timeStep*/)
+{
+ if (m_InputOutputPair.first == inputAtTimeStep)
+ {
+ return m_InputOutputPair.second;
+ }
+ std::string inDir, outDir, inputImagePath, outputImagePath, scriptPath;
+ std::string templateFilename = "XXXXXX_000_0000.nii.gz";
+
+ ProcessExecutor::Pointer spExec = ProcessExecutor::New();
+ itk::CStyleCommand::Pointer spCommand = itk::CStyleCommand::New();
+ spCommand->SetCallback(&onPythonProcessEvent);
+ spExec->AddObserver(ExternalProcessOutputEvent(), spCommand);
+ ProcessExecutor::ArgumentListType args;
+
+ inDir = IOUtil::CreateTemporaryDirectory("nnunet-in-XXXXXX", this->GetMitkTempDir());
+ std::ofstream tmpStream;
+ inputImagePath = IOUtil::CreateTemporaryFile(tmpStream, templateFilename, inDir + IOUtil::GetDirectorySeparator());
+ tmpStream.close();
+ std::size_t found = inputImagePath.find_last_of(IOUtil::GetDirectorySeparator());
+ std::string fileName = inputImagePath.substr(found + 1);
+ std::string token = fileName.substr(0, fileName.find("_"));
+
+ if (this->GetNoPip())
+ {
+ scriptPath = this->GetnnUNetDirectory() + IOUtil::GetDirectorySeparator() + "nnunet" +
+ IOUtil::GetDirectorySeparator() + "inference" + IOUtil::GetDirectorySeparator() + "predict_simple.py";
+ }
+
+ try
+ {
+ IOUtil::Save(inputAtTimeStep, inputImagePath);
+
+ if (this->GetMultiModal())
+ {
+ for (size_t i = 0; i < this->m_OtherModalPaths.size(); ++i)
+ {
+ mitk::Image::ConstPointer modalImage = this->m_OtherModalPaths[i];
+ std::string outModalFile =
+ inDir + IOUtil::GetDirectorySeparator() + token + "_000_000" + std::to_string(i + 1) + ".nii.gz";
+ IOUtil::Save(modalImage.GetPointer(), outModalFile);
+ }
+ }
+ }
+ catch (const mitk::Exception &e)
+ {
+ /*
+ Can't throw mitk exception to the caller. Refer: T28691
+ */
+ MITK_ERROR << e.GetDescription();
+ return nullptr;
+ }
+ // Code calls external process
+ std::string command = "nnUNet_predict";
+ if (this->GetNoPip())
+ {
+#ifdef _WIN32
+ command = "python";
+#else
+ command = "python3";
+#endif
+ }
+ for (ModelParams &modelparam : m_ParamQ)
+ {
+ outDir = IOUtil::CreateTemporaryDirectory("nnunet-out-XXXXXX", this->GetMitkTempDir());
+ outputImagePath = outDir + IOUtil::GetDirectorySeparator() + token + "_000.nii.gz";
+ modelparam.outputDir = outDir;
+ args.clear();
+ if (this->GetNoPip())
+ {
+ args.push_back(scriptPath);
+ }
+ args.push_back("-i");
+ args.push_back(inDir);
+
+ args.push_back("-o");
+ args.push_back(outDir);
+
+ args.push_back("-t");
+ args.push_back(modelparam.task);
+
+ if (modelparam.model.find("cascade") != std::string::npos)
+ {
+ args.push_back("-ctr");
+ }
+ else
+ {
+ args.push_back("-tr");
+ }
+ args.push_back(modelparam.trainer);
+
+ args.push_back("-m");
+ args.push_back(modelparam.model);
+
+ args.push_back("-p");
+ args.push_back(modelparam.planId);
+
+ if (!modelparam.folds.empty())
+ {
+ args.push_back("-f");
+ for (auto fold : modelparam.folds)
+ {
+ args.push_back(fold);
+ }
+ }
+
+ args.push_back("--num_threads_nifti_save");
+ args.push_back("1"); // fixing to 1
+
+ if (!this->GetMirror())
+ {
+ args.push_back("--disable_tta");
+ }
+
+ if (!this->GetMixedPrecision())
+ {
+ args.push_back("--disable_mixed_precision");
+ }
+
+ if (this->GetEnsemble() && !this->GetPostProcessingJsonDirectory().empty())
+ {
+ args.push_back("--save_npz");
+ }
+
+ try
+ {
+ std::string resultsFolderEnv = "RESULTS_FOLDER=" + this->GetModelDirectory();
+ itksys::SystemTools::PutEnv(resultsFolderEnv.c_str());
+ std::string cudaEnv = "CUDA_VISIBLE_DEVICES=" + std::to_string(this->GetGpuId());
+ itksys::SystemTools::PutEnv(cudaEnv.c_str());
+
+ spExec->Execute(this->GetPythonPath(), command, args);
+ }
+ catch (const mitk::Exception &e)
+ {
+ /*
+ Can't throw mitk exception to the caller. Refer: T28691
+ */
+ MITK_ERROR << e.GetDescription();
+ return nullptr;
+ }
+ }
+ if (this->GetEnsemble() && !this->GetPostProcessingJsonDirectory().empty())
+ {
+ args.clear();
+ command = "nnUNet_ensemble";
+ outDir = IOUtil::CreateTemporaryDirectory("nnunet-ensemble-out-XXXXXX", this->GetMitkTempDir());
+ outputImagePath = outDir + IOUtil::GetDirectorySeparator() + token + "_000.nii.gz";
+
+ args.push_back("-f");
+ for (ModelParams &modelparam : m_ParamQ)
+ {
+ args.push_back(modelparam.outputDir);
+ }
+
+ args.push_back("-o");
+ args.push_back(outDir);
+
+ args.push_back("-pp");
+ args.push_back(this->GetPostProcessingJsonDirectory());
+
+ spExec->Execute(this->GetPythonPath(), command, args);
+ }
+ try
+ {
+ LabelSetImage::Pointer resultImage = LabelSetImage::New();
+ Image::Pointer outputImage = IOUtil::Load(outputImagePath);
+ resultImage->InitializeByLabeledImage(outputImage);
+ resultImage->SetGeometry(inputAtTimeStep->GetGeometry());
+ m_InputOutputPair = std::make_pair(inputAtTimeStep, resultImage);
+ return resultImage;
+ }
+ catch (const mitk::Exception &e)
+ {
+ /*
+ Can't throw mitk exception to the caller. Refer: T28691
+ */
+ MITK_ERROR << e.GetDescription();
+ return nullptr;
+ }
+}
diff --git a/Modules/Segmentation/Interactions/mitknnUnetTool.h b/Modules/Segmentation/Interactions/mitknnUnetTool.h
new file mode 100644
index 0000000000..9e5a31cac3
--- /dev/null
+++ b/Modules/Segmentation/Interactions/mitknnUnetTool.h
@@ -0,0 +1,196 @@
+/*============================================================================
+
+The Medical Imaging Interaction Toolkit (MITK)
+
+Copyright (c) German Cancer Research Center (DKFZ)
+All rights reserved.
+
+Use of this source code is governed by a 3-clause BSD license that can be
+found in the LICENSE file.
+
+============================================================================*/
+
+#ifndef mitknnUnetTool_h_Included
+#define mitknnUnetTool_h_Included
+
+#include "mitkAutoMLSegmentationWithPreviewTool.h"
+#include "mitkCommon.h"
+#include "mitkToolManager.h"
+#include
+#include
+#include
+
+namespace us
+{
+ class ModuleResource;
+}
+
+namespace mitk
+{
+ /**
+ * @brief nnUNet parameter request object holding all model parameters for input.
+ * Also holds output temporary directory path.
+ */
+ struct ModelParams
+ {
+ std::string task;
+ std::vector folds;
+ std::string model;
+ std::string trainer;
+ std::string planId;
+ std::string outputDir;
+ };
+
+ /**
+ \brief nnUNet segmentation tool.
+
+ \ingroup Interaction
+ \ingroup ToolManagerEtAl
+
+ \warning Only to be instantiated by mitk::ToolManager.
+ */
+ class MITKSEGMENTATION_EXPORT nnUNetTool : public AutoMLSegmentationWithPreviewTool
+ {
+ public:
+ mitkClassMacro(nnUNetTool, AutoMLSegmentationWithPreviewTool);
+ itkFactorylessNewMacro(Self);
+ itkCloneMacro(Self);
+
+ const char **GetXPM() const override;
+ const char *GetName() const override;
+ us::ModuleResource GetIconResource() const override;
+
+ void Activated() override;
+
+ itkSetMacro(nnUNetDirectory, std::string);
+ itkGetConstMacro(nnUNetDirectory, std::string);
+
+ itkSetMacro(ModelDirectory, std::string);
+ itkGetConstMacro(ModelDirectory, std::string);
+
+ itkSetMacro(PythonPath, std::string);
+ itkGetConstMacro(PythonPath, std::string);
+
+ itkSetMacro(MitkTempDir, std::string);
+ itkGetConstMacro(MitkTempDir, std::string);
+
+ itkSetMacro(PostProcessingJsonDirectory, std::string);
+ itkGetConstMacro(PostProcessingJsonDirectory, std::string);
+
+ itkSetMacro(MixedPrecision, bool);
+ itkGetConstMacro(MixedPrecision, bool);
+ itkBooleanMacro(MixedPrecision);
+
+ itkSetMacro(Mirror, bool);
+ itkGetConstMacro(Mirror, bool);
+ itkBooleanMacro(Mirror);
+
+ itkSetMacro(MultiModal, bool);
+ itkGetConstMacro(MultiModal, bool);
+ itkBooleanMacro(MultiModal);
+
+ itkSetMacro(NoPip, bool);
+ itkGetConstMacro(NoPip, bool);
+ itkBooleanMacro(NoPip);
+
+ itkSetMacro(Ensemble, bool);
+ itkGetConstMacro(Ensemble, bool);
+ itkBooleanMacro(Ensemble);
+
+ itkSetMacro(Predict, bool);
+ itkGetConstMacro(Predict, bool);
+ itkBooleanMacro(Predict);
+
+ itkSetMacro(GpuId, unsigned int);
+ itkGetConstMacro(GpuId, unsigned int);
+
+ /**
+ * @brief vector of ModelParams.
+ * Size > 1 only for ensemble prediction.
+ */
+ std::vector m_ParamQ;
+
+ /**
+ * @brief Holds paths to other input image modalities.
+ *
+ */
+ std::vector m_OtherModalPaths;
+
+ std::pair m_InputOutputPair;
+
+ /**
+ * @brief Renders the output LabelSetImage.
+ * To called in the main thread.
+ */
+ void RenderOutputBuffer();
+
+ /**
+ * @brief Get the Output Buffer object
+ *
+ * @return LabelSetImage::Pointer
+ */
+ LabelSetImage::Pointer GetOutputBuffer();
+
+ /**
+ * @brief Sets the outputBuffer to nullptr
+ *
+ */
+ void ClearOutputBuffer();
+
+ /**
+ * @brief Returns the DataStorage from the ToolManager
+ */
+ mitk::DataStorage *GetDataStorage();
+
+ mitk::DataNode *GetRefNode();
+
+ protected:
+ /**
+ * @brief Construct a new nnUNet Tool object and temp directory.
+ *
+ */
+ nnUNetTool();
+
+ /**
+ * @brief Destroy the nnUNet Tool object and deletes the temp directory.
+ *
+ */
+ ~nnUNetTool();
+
+ /**
+ * @brief Overriden method from the tool manager to execute the segmentation
+ * Implementation:
+ * 1. Saves the inputAtTimeStep in a temporary directory.
+ * 2. Copies other modalities, renames and saves in the temporary directory, if required.
+ * 3. Sets RESULTS_FOLDER and CUDA_VISIBLE_DEVICES variables in the environment.
+ * 3. Iterates through the parameter queue (m_ParamQ) and executes "nnUNet_predict" command with the parameters
+ * 4. Expects an output image to be saved in the temporary directory by the python proces. Loads it as
+ * LabelSetImage and returns.
+ *
+ * @param inputAtTimeStep
+ * @param timeStep
+ * @return LabelSetImage::Pointer
+ */
+ LabelSetImage::Pointer ComputeMLPreview(const Image *inputAtTimeStep, TimeStepType timeStep) override;
+ void UpdateCleanUp() override;
+ void SetNodeProperties(LabelSetImage::Pointer) override;
+
+ private:
+ std::string m_MitkTempDir;
+ std::string m_nnUNetDirectory;
+ std::string m_ModelDirectory;
+ std::string m_PythonPath;
+ std::string m_PostProcessingJsonDirectory;
+ // bool m_UseGPU; kept for future
+ // bool m_AllInGPU;
+ bool m_MixedPrecision;
+ bool m_Mirror;
+ bool m_NoPip;
+ bool m_MultiModal;
+ bool m_Ensemble = false;
+ bool m_Predict;
+ LabelSetImage::Pointer m_OutputBuffer;
+ unsigned int m_GpuId;
+ };
+} // namespace mitk
+#endif
diff --git a/Modules/Segmentation/files.cmake b/Modules/Segmentation/files.cmake
index c4c3643e85..02b759d7b4 100644
--- a/Modules/Segmentation/files.cmake
+++ b/Modules/Segmentation/files.cmake
@@ -1,115 +1,117 @@
set(CPP_FILES
Algorithms/mitkCalculateSegmentationVolume.cpp
Algorithms/mitkContourModelSetToImageFilter.cpp
Algorithms/mitkContourSetToPointSetFilter.cpp
Algorithms/mitkContourUtils.cpp
Algorithms/mitkCorrectorAlgorithm.cpp
Algorithms/mitkDiffImageApplier.cpp
Algorithms/mitkDiffSliceOperation.cpp
Algorithms/mitkDiffSliceOperationApplier.cpp
Algorithms/mitkFeatureBasedEdgeDetectionFilter.cpp
Algorithms/mitkImageLiveWireContourModelFilter.cpp
Algorithms/mitkImageToContourFilter.cpp
#Algorithms/mitkImageToContourModelFilter.cpp
Algorithms/mitkImageToLiveWireContourFilter.cpp
Algorithms/mitkManualSegmentationToSurfaceFilter.cpp
Algorithms/mitkOtsuSegmentationFilter.cpp
Algorithms/mitkSegmentationObjectFactory.cpp
Algorithms/mitkShapeBasedInterpolationAlgorithm.cpp
Algorithms/mitkShowSegmentationAsSmoothedSurface.cpp
Algorithms/mitkShowSegmentationAsSurface.cpp
Algorithms/mitkVtkImageOverwrite.cpp
Controllers/mitkSegmentationInterpolationController.cpp
Controllers/mitkToolManager.cpp
Controllers/mitkSegmentationModuleActivator.cpp
Controllers/mitkToolManagerProvider.cpp
DataManagement/mitkContour.cpp
DataManagement/mitkContourSet.cpp
DataManagement/mitkExtrudedContour.cpp
Interactions/mitkAdaptiveRegionGrowingTool.cpp
Interactions/mitkAddContourTool.cpp
Interactions/mitkAutoCropTool.cpp
Interactions/mitkAutoSegmentationTool.cpp
Interactions/mitkAutoSegmentationWithPreviewTool.cpp
Interactions/mitkAutoMLSegmentationWithPreviewTool.cpp
Interactions/mitkBinaryThresholdBaseTool.cpp
Interactions/mitkBinaryThresholdTool.cpp
Interactions/mitkBinaryThresholdULTool.cpp
Interactions/mitkCalculateGrayValueStatisticsTool.cpp
Interactions/mitkCalculateVolumetryTool.cpp
Interactions/mitkContourModelInteractor.cpp
Interactions/mitkContourModelLiveWireInteractor.cpp
Interactions/mitkLiveWireTool2D.cpp
Interactions/mitkContourTool.cpp
Interactions/mitkCreateSurfaceTool.cpp
Interactions/mitkDrawPaintbrushTool.cpp
Interactions/mitkErasePaintbrushTool.cpp
Interactions/mitkEraseRegionTool.cpp
Interactions/mitkFastMarchingBaseTool.cpp
Interactions/mitkFastMarchingTool.cpp
Interactions/mitkFastMarchingTool3D.cpp
Interactions/mitkFeedbackContourTool.cpp
Interactions/mitkFillRegionTool.cpp
Interactions/mitkOtsuTool3D.cpp
Interactions/mitkPaintbrushTool.cpp
Interactions/mitkPixelManipulationTool.cpp
Interactions/mitkRegionGrowingTool.cpp
Interactions/mitkSegmentationsProcessingTool.cpp
Interactions/mitkSetRegionTool.cpp
Interactions/mitkSegTool2D.cpp
Interactions/mitkSubtractContourTool.cpp
Interactions/mitkTool.cpp
Interactions/mitkToolCommand.cpp
Interactions/mitkWatershedTool.cpp
Interactions/mitkPickingTool.cpp
+ Interactions/mitknnUnetTool.cpp
Interactions/mitkSegmentationInteractor.cpp #SO
+ Interactions/mitkProcessExecutor.cpp
Rendering/mitkContourMapper2D.cpp
Rendering/mitkContourSetMapper2D.cpp
Rendering/mitkContourSetVtkMapper3D.cpp
Rendering/mitkContourVtkMapper3D.cpp
SegmentationUtilities/BooleanOperations/mitkBooleanOperation.cpp
SegmentationUtilities/MorphologicalOperations/mitkMorphologicalOperations.cpp
#Added from ML
Controllers/mitkSliceBasedInterpolationController.cpp
Algorithms/mitkSurfaceStampImageFilter.cpp
)
set(RESOURCE_FILES
Add_48x48.png
Add_Cursor_32x32.png
Erase_48x48.png
Erase_Cursor_32x32.png
FastMarching_48x48.png
FastMarching_Cursor_32x32.png
Fill_48x48.png
Fill_Cursor_32x32.png
LiveWire_48x48.png
LiveWire_Cursor_32x32.png
Otsu_48x48.png
Paint_48x48.png
Paint_Cursor_32x32.png
Pick_48x48.png
RegionGrowing_48x48.png
RegionGrowing_Cursor_32x32.png
Subtract_48x48.png
Subtract_Cursor_32x32.png
Threshold_48x48.png
TwoThresholds_48x48.png
Watershed_48x48.png
Watershed_Cursor_32x32.png
Wipe_48x48.png
Wipe_Cursor_32x32.png
Interactions/dummy.xml
Interactions/LiveWireTool.xml
Interactions/FastMarchingTool.xml
Interactions/PickingTool.xml
Interactions/PressMoveRelease.xml
Interactions/PressMoveReleaseAndPointSetting.xml
Interactions/PressMoveReleaseWithCTRLInversion.xml
Interactions/PressMoveReleaseWithCTRLInversionAllMouseMoves.xml
Interactions/SegmentationToolsConfig.xml
Interactions/ContourModelModificationConfig.xml
Interactions/ContourModelModificationInteractor.xml
)
diff --git a/Modules/SegmentationUI/Qmitk/QmitknnUNetEnsembleLayout.h b/Modules/SegmentationUI/Qmitk/QmitknnUNetEnsembleLayout.h
new file mode 100644
index 0000000000..881cb52567
--- /dev/null
+++ b/Modules/SegmentationUI/Qmitk/QmitknnUNetEnsembleLayout.h
@@ -0,0 +1,86 @@
+/*============================================================================
+
+The Medical Imaging Interaction Toolkit (MITK)
+
+Copyright (c) German Cancer Research Center (DKFZ)
+All rights reserved.
+
+Use of this source code is governed by a 3-clause BSD license that can be
+found in the LICENSE file.s
+
+============================================================================*/
+
+#ifndef QmitknnUNetEnsembleLayout_h_Included
+#define QmitknnUNetEnsembleLayout_h_Included
+
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+QT_BEGIN_NAMESPACE
+
+class MITKSEGMENTATIONUI_EXPORT QmitknnUNetTaskParamsUITemplate
+{
+
+public:
+ QLabel* trainerLabel;
+ ctkComboBox* trainerBox;
+ QLabel* plannerLabel;
+ ctkComboBox* plannerBox;
+ QLabel* foldLabel;
+ ctkCheckableComboBox* foldBox;
+ QLabel* modelLabel;
+ ctkComboBox* modelBox;
+ QWidget* parent;
+
+ QmitknnUNetTaskParamsUITemplate(QWidget* inputGroupBox_1)
+ {
+ this->parent = inputGroupBox_1;
+ QVBoxLayout* verticalLayout_x = new QVBoxLayout(inputGroupBox_1);
+ verticalLayout_x->setObjectName(QString::fromUtf8("verticalLayout_x"));
+ QGridLayout* g_x = new QGridLayout();
+#ifndef Q_OS_MAC
+ g_x->setSpacing(6);
+#endif
+#ifndef Q_OS_MAC
+ g_x->setContentsMargins(0, 0, 0, 0);
+#endif
+ g_x->setObjectName(QString::fromUtf8("g_2"));
+
+ modelLabel = new QLabel("Configuration", inputGroupBox_1);
+ g_x->addWidget(modelLabel, 0, 0, 1, 1);
+ trainerLabel = new QLabel("Trainer", inputGroupBox_1);
+ g_x->addWidget(trainerLabel, 0, 1, 1, 1);
+
+ modelBox = new ctkComboBox(inputGroupBox_1);
+ modelBox->setObjectName(QString::fromUtf8("modelBox_1"));
+ g_x->addWidget(modelBox, 1, 0, 1, 1);
+ trainerBox = new ctkComboBox(inputGroupBox_1);
+ trainerBox->setObjectName(QString::fromUtf8("trainerBox_1"));
+ g_x->addWidget(trainerBox, 1, 1, 1, 1);
+
+ plannerLabel = new QLabel("Planner", inputGroupBox_1);
+ g_x->addWidget(plannerLabel, 2, 0, 1, 1);
+ foldLabel = new QLabel("Fold", inputGroupBox_1);
+ g_x->addWidget(foldLabel, 2, 1, 1, 1);
+
+ plannerBox = new ctkComboBox(inputGroupBox_1);
+ plannerBox->setObjectName(QString::fromUtf8("plannerBox_1"));
+ g_x->addWidget(plannerBox, 3, 0, 1, 1);
+ foldBox = new ctkCheckableComboBox(inputGroupBox_1);
+ foldBox->setObjectName(QString::fromUtf8("foldBox_1"));
+ g_x->addWidget(foldBox, 3, 1, 1, 1);
+
+ verticalLayout_x->addLayout(g_x);
+ }
+};
+QT_END_NAMESPACE
+
+#endif
+
diff --git a/Modules/SegmentationUI/Qmitk/QmitknnUNetFolderParser.h b/Modules/SegmentationUI/Qmitk/QmitknnUNetFolderParser.h
new file mode 100644
index 0000000000..d005f62eb3
--- /dev/null
+++ b/Modules/SegmentationUI/Qmitk/QmitknnUNetFolderParser.h
@@ -0,0 +1,281 @@
+/*============================================================================
+
+The Medical Imaging Interaction Toolkit (MITK)
+
+Copyright (c) German Cancer Research Center (DKFZ)
+All rights reserved.
+
+Use of this source code is governed by a 3-clause BSD license that can be
+found in the LICENSE file.s
+
+============================================================================*/
+
+#ifndef QmitknnUNetFolderParser_h_Included
+#define QmitknnUNetFolderParser_h_Included
+
+#include "QmitknnUNetToolGUI.h"
+#include
+#include
+#include
+
+/**
+ * @brief Struct to store each (Folder) Node of the hierarchy tree structure.
+ *
+ */
+struct FolderNode
+{
+ QString name;
+ QString path; // parent
+ std::vector> subFolders;
+};
+
+/**
+ * @brief Class to store and retreive folder hierarchy information
+ * of RESULTS_FOLDER. Only Root node is explicitly stored in m_RootNode.
+ * No. of sub levels in the hierachry is defined in the LEVEL constant.
+ *
+ */
+class MITKSEGMENTATIONUI_EXPORT QmitknnUNetFolderParser
+{
+public:
+
+ /**
+ * @brief Construct a new QmitknnUNetFolderParser object
+ * Initializes root folder node object pointer calls
+ * @param parentFolder
+ */
+ QmitknnUNetFolderParser(const QString parentFolder)
+ {
+ m_RootNode = std::make_shared();
+ m_RootNode->path = parentFolder;
+ m_RootNode->name = QString("nnUNet");
+ m_RootNode->subFolders.clear();
+ InitDirs(m_RootNode, 0);
+ }
+
+ /**
+ * @brief Destroy the QmitknnUNetFolderParser object
+ *
+ */
+ ~QmitknnUNetFolderParser() = default; /*{ DeleteDirs(m_RootNode, LEVEL); }*/
+
+ /**
+ * @brief Returns the "Results Folder" string which is parent path of the root node.
+ *
+ * @return QString
+ */
+ QString getResultsFolder() { return m_RootNode->path; }
+
+ /**
+ * @brief Returns the Model Names from root node. Template function,
+ * type can be any of stl or Qt containers which supports push_back call.
+ *
+ * @tparam T
+ * @return T (any of stl or Qt containers which supports push_back call)
+ */
+ template
+ T getModelNames()
+ {
+ auto models = GetSubFolderNamesFromNode(m_RootNode);
+ return models;
+ }
+
+ /**
+ * @brief Returns the task names for a given model. Template function,
+ * type can be any of stl or Qt containers which supports push_back call.
+ *
+ * @tparam T
+ * @param modelName
+ * @return T (any of stl or Qt containers which supports push_back call)
+ */
+ template
+ T getTasksForModel(const QString &modelName)
+ {
+ std::shared_ptr modelNode = GetSubNodeMatchingNameCrietria(modelName, m_RootNode);
+ auto tasks = GetSubFolderNamesFromNode(modelNode);
+ return tasks;
+ }
+
+ /**
+ * @brief Returns the models names for a given task. Template function,
+ * type can be any of stl or Qt containers which supports push_back call.
+ *
+ * @tparam T
+ * @param taskName
+ * @return T (any of stl or Qt containers which supports push_back call)
+ */
+ template
+ T getModelsForTask(const QString &taskName)
+ {
+ T modelsForTask;
+ auto models = GetSubFolderNamesFromNode(m_RootNode);
+ foreach (QString model, models)
+ {
+ QStringList taskList = getTasksForModel(model);
+ if (taskList.contains(taskName, Qt::CaseInsensitive))
+ {
+ modelsForTask << model;
+ }
+ }
+ return modelsForTask;
+ }
+
+ /**
+ * @brief Returns the trainer / planner names for a given task & model. Template function,
+ * type can be any of stl or Qt containers which supports push_back call.
+ *
+ * @tparam T
+ * @param taskName
+ * @param modelName
+ * @return T (any of stl or Qt containers which supports push_back call)
+ */
+ template
+ T getTrainerPlannersForTask(const QString &taskName, const QString &modelName)
+ {
+ std::shared_ptr modelNode = GetSubNodeMatchingNameCrietria(modelName, m_RootNode);
+ std::shared_ptr taskNode = GetSubNodeMatchingNameCrietria(taskName, modelNode);
+ auto tps = GetSubFolderNamesFromNode(taskNode);
+ return tps;
+ }
+
+ /**
+ * @brief Returns the Folds names for a given trainer,planner,task & model name. Template function,
+ * type can be any of stl or Qt containers which supports push_back call.
+ *
+ * @tparam T
+ * @param trainer
+ * @param planner
+ * @param taskName
+ * @param modelName
+ * @return T (any of stl or Qt containers which supports push_back call)
+ */
+ template
+ T getFoldsForTrainerPlanner(const QString &trainer,
+ const QString &planner,
+ const QString &taskName,
+ const QString &modelName)
+ {
+ std::shared_ptr modelNode = GetSubNodeMatchingNameCrietria(modelName, m_RootNode);
+ std::shared_ptr taskNode = GetSubNodeMatchingNameCrietria(taskName, modelNode);
+ QString trainerPlanner = trainer + QString("__") + planner;
+ std::shared_ptr tpNode = GetSubNodeMatchingNameCrietria(trainerPlanner, taskNode);
+ auto folds = GetSubFolderNamesFromNode(tpNode);
+ return folds;
+ }
+
+private:
+ const int m_LEVEL = 4;
+ std::shared_ptr m_RootNode;
+
+ /**
+ * @brief Iterates through the root node and returns the sub FolderNode object Matching Name Crietria
+ *
+ * @param queryName
+ * @param parentNode
+ * @return std::shared_ptr
+ */
+ std::shared_ptr GetSubNodeMatchingNameCrietria(const QString &queryName,
+ std::shared_ptr parentNode)
+ {
+ std::shared_ptr retNode;
+ std::vector> subNodes = parentNode->subFolders;
+ for (std::shared_ptr node : subNodes)
+ {
+ if (node->name == queryName)
+ {
+ retNode = node;
+ break;
+ }
+ }
+ return retNode;
+ }
+
+ /**
+ * @brief Returns the sub folder names for a folder node object. Template function,
+ * type can be any of stl or Qt containers which supports push_back call.
+ *
+ * @tparam T
+ * @param std::shared_ptr
+ * @return T (any of stl or Qt containers which supports push_back call)
+ */
+ template
+ T GetSubFolderNamesFromNode(const std::shared_ptr parent)
+ {
+ T folders;
+ std::vector> subNodes = parent->subFolders;
+ for (std::shared_ptr folder : subNodes)
+ {
+ folders.push_back(folder->name);
+ }
+ return folders;
+ }
+
+ /**
+ * @brief Iterates through the sub folder hierarchy upto a level provided
+ * and create a tree structure.
+ *
+ * @param parent
+ * @param level
+ */
+ void InitDirs(std::shared_ptr parent, int level)
+ {
+ QString searchFolder = parent->path + QDir::separator() + parent->name;
+ auto subFolders = FetchFoldersFromDir