diff --git a/Applications/Diffusion/CMakeLists.txt b/Applications/Diffusion/CMakeLists.txt
index 903b7d2193..fc47284c90 100644
--- a/Applications/Diffusion/CMakeLists.txt
+++ b/Applications/Diffusion/CMakeLists.txt
@@ -1,95 +1,96 @@
 project(MitkDiffusion)
 
 set(DIFFUSIONAPP_NAME MitkDiffusion)
 
 set(_app_options)
 if(MITK_SHOW_CONSOLE_WINDOW)
   list(APPEND _app_options SHOW_CONSOLE)
 endif()
 
 # Create a cache entry for the provisioning file which is used to export
 # the file name in the MITKConfig.cmake file. This will keep external projects
 # which rely on this file happy.
 set(DIFFUSIONIMAGINGAPP_PROVISIONING_FILE "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${DIFFUSIONAPP_NAME}.provisioning" CACHE INTERNAL "${DIFFUSIONAPP_NAME} provisioning file" FORCE)
 
 # should be identical to the list in /CMake/mitkBuildConfigurationmitkDiffusion.cmake
 # remember to set plugins which should be automatically toggled in target_libraries.cmake
 set(_plugins
   org.commontk.configadmin
   org.commontk.eventadmin
   org.blueberry.core.runtime
   org.blueberry.core.expressions
   org.blueberry.core.commands
   org.blueberry.ui.qt
   org.blueberry.ui.qt.log
   org.blueberry.ui.qt.help
   org.mitk.core.services
   org.mitk.gui.common
   org.mitk.planarfigure
   org.mitk.core.ext
   org.mitk.gui.qt.application
   org.mitk.gui.qt.ext
   org.mitk.gui.qt.diffusionimagingapp
   org.mitk.gui.qt.common
   org.mitk.gui.qt.stdmultiwidgeteditor
   org.mitk.gui.qt.common.legacy
   org.mitk.gui.qt.datamanager
   org.mitk.gui.qt.measurementtoolbox
   org.mitk.gui.qt.segmentation
   org.mitk.gui.qt.volumevisualization
   org.mitk.gui.qt.diffusionimaging
   org.mitk.gui.qt.diffusionimaging.connectomics
   org.mitk.gui.qt.diffusionimaging.fiberfox
   org.mitk.gui.qt.diffusionimaging.fiberprocessing
   org.mitk.gui.qt.diffusionimaging.ivim
   org.mitk.gui.qt.diffusionimaging.odfpeaks
   org.mitk.gui.qt.diffusionimaging.preprocessing
   org.mitk.gui.qt.diffusionimaging.reconstruction
   org.mitk.gui.qt.diffusionimaging.tractography
   org.mitk.gui.qt.matchpoint.algorithm.browser
   org.mitk.gui.qt.matchpoint.algorithm.control
+  org.mitk.gui.qt.matchpoint.mapper
   org.mitk.gui.qt.imagenavigator
   org.mitk.gui.qt.moviemaker
   org.mitk.gui.qt.basicimageprocessing
   org.mitk.gui.qt.properties
   org.mitk.gui.qt.viewnavigator
 )
 
 # Plug-ins listed below will not be
 #  - added as a build-time dependency to the executable
 #  - listed in the provisioning file for the executable
 #  - installed if they are external plug-ins
 
 set(_exclude_plugins
   org.blueberry.test
   org.blueberry.uitest
   org.mitk.gui.qt.coreapplication
   org.mitk.gui.qt.extapplication
 )
 
 set(_src_files
   MitkDiffusion.cpp
 )
 
 qt5_add_resources(_src_files splashscreen.qrc)
 
 mitkFunctionCreateBlueBerryApplication(
   NAME ${DIFFUSIONAPP_NAME}
   DESCRIPTION "MITK Diffusion"
   PLUGINS ${_plugins}
   EXCLUDE_PLUGINS ${_exclude_plugins}
   SOURCES ${_src_files}
   ${_app_options}
 )
 
 mitk_use_modules(TARGET ${DIFFUSIONAPP_NAME} MODULES MitkAppUtil)
 
 # Add meta dependencies (e.g. on auto-load modules from depending modules)
 if(TARGET ${CMAKE_PROJECT_NAME}-autoload)
   add_dependencies(${DIFFUSIONAPP_NAME} ${CMAKE_PROJECT_NAME}-autoload)
 endif()
 
 # Add a build time dependency to legacy BlueBerry bundles.
 if(MITK_MODULES_ENABLED_PLUGINS)
   add_dependencies(${DIFFUSIONAPP_NAME} ${MITK_MODULES_ENABLED_PLUGINS})
 endif()
diff --git a/Applications/Diffusion/target_libraries.cmake b/Applications/Diffusion/target_libraries.cmake
index a6496917be..347d5fbc04 100644
--- a/Applications/Diffusion/target_libraries.cmake
+++ b/Applications/Diffusion/target_libraries.cmake
@@ -1,29 +1,32 @@
 
 # A list of plug-in targets which should be automatically enabled
-# (or be available in external projects) for this application.
+# (or be available in external projects) for this application
 
 set(target_libraries
   org_blueberry_ui_qt
   org_blueberry_ui_qt_help
   org_mitk_planarfigure
   org_mitk_gui_qt_diffusionimagingapp
   org_mitk_gui_qt_common_legacy
   org_mitk_gui_qt_ext
   org_mitk_gui_qt_datamanager
   org_mitk_gui_qt_segmentation
   org_mitk_gui_qt_volumevisualization
   org_mitk_gui_qt_diffusionimaging
   org_mitk_gui_qt_diffusionimaging_connectomics
   org_mitk_gui_qt_diffusionimaging_fiberfox
   org_mitk_gui_qt_diffusionimaging_fiberprocessing
   org_mitk_gui_qt_diffusionimaging_ivim
   org_mitk_gui_qt_diffusionimaging_odfpeaks
   org_mitk_gui_qt_diffusionimaging_preprocessing
   org_mitk_gui_qt_diffusionimaging_reconstruction
   org_mitk_gui_qt_diffusionimaging_tractography
+  org_mitk_gui_qt_matchpoint_algorithm_browser
+  org_mitk_gui_qt_matchpoint_algorithm_control
+  org_mitk_gui_qt_matchpoint_mapper
   org_mitk_gui_qt_imagenavigator
   org_mitk_gui_qt_moviemaker
   org_mitk_gui_qt_measurementtoolbox
   org_mitk_gui_qt_basicimageprocessing
   org_mitk_gui_qt_viewnavigator
 )
diff --git a/CMake/BuildConfigurations/mitkDiffusion.cmake b/CMake/BuildConfigurations/DiffusionAll.cmake
similarity index 94%
rename from CMake/BuildConfigurations/mitkDiffusion.cmake
rename to CMake/BuildConfigurations/DiffusionAll.cmake
index 5e00e6b54b..26f661e2c9 100644
--- a/CMake/BuildConfigurations/mitkDiffusion.cmake
+++ b/CMake/BuildConfigurations/DiffusionAll.cmake
@@ -1,35 +1,34 @@
-message(STATUS "Configuring MITK Diffusion Release Build")
+message(STATUS "Configuring MITK Diffusion with all Plugins")
 
 # Enable non-optional external dependencies
 set(MITK_USE_Vigra ON CACHE BOOL "MITK Use Vigra Library" FORCE)
 set(MITK_USE_HDF5 ON CACHE BOOL "MITK Use HDF5 Library" FORCE)
 set(MITK_USE_DCMQI ON CACHE BOOL "" FORCE)
 set(MITK_USE_MatchPoint ON CACHE BOOL "" FORCE)
 
 # Disable all apps but MITK Diffusion
 set(MITK_BUILD_ALL_APPS OFF CACHE BOOL "Build all MITK applications" FORCE)
 set(MITK_BUILD_APP_CoreApp OFF CACHE BOOL "Build the MITK CoreApp" FORCE)
-set(MITK_BUILD_APP_Workbench OFF CACHE BOOL "Build the MITK Workbench" FORCE)
 set(MITK_BUILD_APP_Diffusion ON CACHE BOOL "Build MITK Diffusion" FORCE)
 
 # Activate Diffusion Mini Apps
 set(BUILD_DiffusionCoreCmdApps ON CACHE BOOL "Build commandline tools for diffusion" FORCE)
 set(BUILD_DiffusionFiberProcessingCmdApps ON CACHE BOOL "Build commandline tools for diffusion fiber processing" FORCE)
 set(BUILD_DiffusionFiberfoxCmdApps ON CACHE BOOL "Build commandline tools for diffusion data simulation (Fiberfox)" FORCE)
 set(BUILD_DiffusionMiscCmdApps ON CACHE BOOL "Build miscellaneous commandline tools for diffusion" FORCE)
 set(BUILD_DiffusionQuantificationCmdApps ON CACHE BOOL "Build commandline tools for diffusion quantification (IVIM, ADC, ...)" FORCE)
 set(BUILD_DiffusionTractographyCmdApps ON CACHE BOOL "Build commandline tools for diffusion fiber tractography" FORCE)
 set(BUILD_DiffusionTractographyEvaluationCmdApps ON CACHE BOOL "Build commandline tools for diffusion fiber tractography evaluation" FORCE)
 set(BUILD_DiffusionConnectomicsCmdApps ON CACHE BOOL "Build commandline tools for diffusion connectomics" FORCE)
 
 # Build neither all plugins nor examples
 set(MITK_BUILD_ALL_PLUGINS OFF CACHE BOOL "Build all MITK plugins" FORCE)
 set(MITK_BUILD_EXAMPLES OFF CACHE BOOL "Build the MITK examples" FORCE)
 set(BUILD_TESTING ON CACHE BOOL "Build the MITK tests" FORCE)
 
 # Activate in-application help generation
 set(MITK_DOXYGEN_GENERATE_QCH_FILES ON CACHE BOOL "Use doxygen to generate Qt compressed help files for MITK docs" FORCE)
 set(BLUEBERRY_USE_QT_HELP ON CACHE BOOL "Enable support for integrating bundle documentation into Qt Help" FORCE)
 
 # Disable console window
 set(MITK_SHOW_CONSOLE_WINDOW ON CACHE BOOL "Use this to enable or disable the console window when starting MITK GUI Applications" FORCE)
diff --git a/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleTckReader.cpp b/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleTckReader.cpp
index 1c5d1ddca6..cc326c9b2c 100644
--- a/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleTckReader.cpp
+++ b/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleTckReader.cpp
@@ -1,166 +1,164 @@
 /*===================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center,
 Division of Medical and Biological Informatics.
 All rights reserved.
 
 This software is distributed WITHOUT ANY WARRANTY; without
 even the implied warranty of MERCHANTABILITY or FITNESS FOR
 A PARTICULAR PURPOSE.
 
 See LICENSE.txt or http://www.mitk.org for details.
 
 ===================================================================*/
 
 #include "mitkFiberBundleTckReader.h"
 #include <itkMetaDataObject.h>
 #include <vtkPolyData.h>
 #include <vtkDataReader.h>
 #include <vtkPolyDataReader.h>
 #include <vtkMatrix4x4.h>
 #include <vtkPolyLine.h>
 #include <vtkCellArray.h>
 #include <vtkDataArray.h>
 #include <vtkFloatArray.h>
 #include <vtkCellData.h>
 #include <vtkPointData.h>
 #include <itksys/SystemTools.hxx>
 #include <tinyxml.h>
 #include <vtkCleanPolyData.h>
 #include <mitkTrackvis.h>
 #include <mitkCustomMimeType.h>
 #include "mitkDiffusionIOMimeTypes.h"
 #include <vtkTransformPolyDataFilter.h>
 #include <boost/lexical_cast.hpp>
 
 
 mitk::FiberBundleTckReader::FiberBundleTckReader()
-    : mitk::AbstractFileReader( mitk::DiffusionIOMimeTypes::FIBERBUNDLE_TCK_MIMETYPE_NAME(), "tck Fiber Bundle Reader (MRtrix format)" )
+  : mitk::AbstractFileReader( mitk::DiffusionIOMimeTypes::FIBERBUNDLE_TCK_MIMETYPE_NAME(), "tck Fiber Bundle Reader (MRtrix format)" )
 {
-    m_ServiceReg = this->RegisterService();
+  m_ServiceReg = this->RegisterService();
 }
 
 mitk::FiberBundleTckReader::FiberBundleTckReader(const FiberBundleTckReader &other)
-    :mitk::AbstractFileReader(other)
+  :mitk::AbstractFileReader(other)
 {
 }
 
 mitk::FiberBundleTckReader * mitk::FiberBundleTckReader::Clone() const
 {
-    return new FiberBundleTckReader(*this);
+  return new FiberBundleTckReader(*this);
 }
 
 std::vector<itk::SmartPointer<mitk::BaseData> > mitk::FiberBundleTckReader::Read()
 {
 
-    std::vector<itk::SmartPointer<mitk::BaseData> > result;
-    try
-    {
-        const std::string& locale = "C";
-        const std::string& currLocale = setlocale( LC_ALL, nullptr );
-        setlocale(LC_ALL, locale.c_str());
+  std::vector<itk::SmartPointer<mitk::BaseData> > result;
+  try
+  {
+    const std::string& locale = "C";
+    const std::string& currLocale = setlocale( LC_ALL, nullptr );
+    setlocale(LC_ALL, locale.c_str());
 
-        std::string filename = this->GetInputLocation();
+    std::string filename = this->GetInputLocation();
 
-        std::string ext = itksys::SystemTools::GetFilenameLastExtension(filename);
-        ext = itksys::SystemTools::LowerCase(ext);
+    std::string ext = itksys::SystemTools::GetFilenameLastExtension(filename);
+    ext = itksys::SystemTools::LowerCase(ext);
 
-        if (ext==".tck")
+    if (ext==".tck")
+    {
+      MITK_INFO << "Loading tractogram (MRtrix format): " << itksys::SystemTools::GetFilenameName(filename);
+      std::FILE* filePointer = std::fopen(filename.c_str(),"r+b");
+      std::string header = "";
+
+      bool header_end = false;
+      int count = 0;
+      while (!header_end)
+      {
+        char c;
+        count += std::fread(&c, 1, 1, filePointer);
+        header += c;
+        if (header.size() >= 3 && header.compare(header.size() - 3, 3, "END") == 0)
+          header_end = true;
+      }
+      MITK_INFO << "TCK Header:";
+      MITK_INFO << header;
+
+      int header_size = -1;
+      try
+      {
+        std::string delimiter = "file: . ";
+        size_t pos = 0;
+        pos = header.find(delimiter);
+        header.erase(0, pos + delimiter.length());
+        pos = header.find("\n");
+        header_size = boost::lexical_cast<int>(header.substr(0, pos));
+      }
+      catch(...)
+      {
+
+      }
+
+      if (header_size==-1)
+        mitkThrow() << "Could not parse header size from " << filename;
+      std::fseek ( filePointer , header_size , SEEK_SET );
+
+      vtkSmartPointer<vtkPoints> vtkNewPoints = vtkSmartPointer<vtkPoints>::New();
+      vtkSmartPointer<vtkCellArray> vtkNewCells = vtkSmartPointer<vtkCellArray>::New();
+      vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New();
+
+      float tmp[3];
+      count = 1;
+      int fiber_length = 0;
+      while (std::fread((char*)tmp, 1, 12, filePointer)==12)
+      {
+        if (std::isinf(tmp[0]) || std::isinf(tmp[1]) || std::isinf(tmp[1]))
+          break;
+        else if (std::isnan(tmp[0]) || std::isnan(tmp[1]) || std::isnan(tmp[2]))
         {
-            std::FILE* filePointer = std::fopen(filename.c_str(),"r+b");
-            std::string header = "";
-
-            bool header_end = false;
-            int count = 0;
-            while (!header_end)
-            {
-              char c;
-              count += std::fread(&c, 1, 1, filePointer);
-              header += c;
-              if (header.size() >= 3 && header.compare(header.size() - 3, 3, "END") == 0)
-                header_end = true;
-            }
-            MITK_INFO << "TCK Header:";
-            MITK_INFO << header;
-
-            int header_size = -1;
-            try
-            {
-                std::string delimiter = "file: . ";
-                size_t pos = 0;
-                pos = header.find(delimiter);
-                header.erase(0, pos + delimiter.length());
-                pos = header.find("\n");
-                header_size = boost::lexical_cast<int>(header.substr(0, pos));
-            }
-            catch(...)
-            {
-
-            }
-
-            if (header_size==-1)
-                mitkThrow() << "Could not parse header size from " << filename;
-            std::fseek ( filePointer , header_size , SEEK_SET );
-
-            MITK_INFO << "Reading TCK file";
-
-
-            vtkSmartPointer<vtkPoints> vtkNewPoints = vtkSmartPointer<vtkPoints>::New();
-            vtkSmartPointer<vtkCellArray> vtkNewCells = vtkSmartPointer<vtkCellArray>::New();
-            vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New();
-
-            float tmp[3];
-            count = 1;
-            int fiber_length = 0;
-            while (std::fread((char*)tmp, 1, 12, filePointer)==12)
-            {
-              if (std::isinf(tmp[0]) || std::isinf(tmp[1]) || std::isinf(tmp[1]))
-                break;
-              else if (std::isnan(tmp[0]) || std::isnan(tmp[1]) || std::isnan(tmp[2]))
-              {
-                count++;
-                fiber_length = 0;
-                vtkNewCells->InsertNextCell(container);
-                container = vtkSmartPointer<vtkPolyLine>::New();
-              }
-              else
-              {
-                fiber_length++;
-                vtkIdType id = vtkNewPoints->InsertNextPoint(tmp);
-                container->GetPointIds()->InsertNextId(id);
-              }
-            }
-
-            vtkSmartPointer<vtkPolyData> fiberPolyData = vtkSmartPointer<vtkPolyData>::New();
-            fiberPolyData->SetPoints(vtkNewPoints);
-            fiberPolyData->SetLines(vtkNewCells);
-
-            // transform polydata from RAS (MRtrix) to LPS (MITK)
-            mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New();
-            vtkSmartPointer< vtkMatrix4x4 > matrix = vtkSmartPointer< vtkMatrix4x4 >::New();
-            matrix->Identity();
-            matrix->SetElement(0,0,-matrix->GetElement(0,0));
-            matrix->SetElement(1,1,-matrix->GetElement(1,1));
-            geometry->SetIndexToWorldTransformByVtkMatrix(matrix);
-
-            vtkSmartPointer<vtkTransformPolyDataFilter> transformFilter = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
-            transformFilter->SetInputData(fiberPolyData);
-            transformFilter->SetTransform(geometry->GetVtkTransform());
-            transformFilter->Update();
-
-            FiberBundle::Pointer fib = FiberBundle::New(transformFilter->GetOutput());
-            result.push_back(fib.GetPointer());
+          count++;
+          fiber_length = 0;
+          vtkNewCells->InsertNextCell(container);
+          container = vtkSmartPointer<vtkPolyLine>::New();
         }
-
-        setlocale(LC_ALL, currLocale.c_str());
-        MITK_INFO << "Fiber bundle read";
-        return result;
-    }
-    catch(...)
-    {
-        throw;
+        else
+        {
+          fiber_length++;
+          vtkIdType id = vtkNewPoints->InsertNextPoint(tmp);
+          container->GetPointIds()->InsertNextId(id);
+        }
+      }
+
+      vtkSmartPointer<vtkPolyData> fiberPolyData = vtkSmartPointer<vtkPolyData>::New();
+      fiberPolyData->SetPoints(vtkNewPoints);
+      fiberPolyData->SetLines(vtkNewCells);
+
+      // transform polydata from RAS (MRtrix) to LPS (MITK)
+      mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New();
+      vtkSmartPointer< vtkMatrix4x4 > matrix = vtkSmartPointer< vtkMatrix4x4 >::New();
+      matrix->Identity();
+      matrix->SetElement(0,0,-matrix->GetElement(0,0));
+      matrix->SetElement(1,1,-matrix->GetElement(1,1));
+      geometry->SetIndexToWorldTransformByVtkMatrix(matrix);
+
+      vtkSmartPointer<vtkTransformPolyDataFilter> transformFilter = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
+      transformFilter->SetInputData(fiberPolyData);
+      transformFilter->SetTransform(geometry->GetVtkTransform());
+      transformFilter->Update();
+
+      FiberBundle::Pointer fib = FiberBundle::New(transformFilter->GetOutput());
+      result.push_back(fib.GetPointer());
     }
+
+    setlocale(LC_ALL, currLocale.c_str());
+    MITK_INFO << "Fiber bundle read";
     return result;
+  }
+  catch(...)
+  {
+    throw;
+  }
+  return result;
 }
diff --git a/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleTrackVisReader.cpp b/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleTrackVisReader.cpp
index 0d02e09733..beac4c8317 100644
--- a/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleTrackVisReader.cpp
+++ b/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleTrackVisReader.cpp
@@ -1,86 +1,87 @@
 /*===================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center,
 Division of Medical and Biological Informatics.
 All rights reserved.
 
 This software is distributed WITHOUT ANY WARRANTY; without
 even the implied warranty of MERCHANTABILITY or FITNESS FOR
 A PARTICULAR PURPOSE.
 
 See LICENSE.txt or http://www.mitk.org for details.
 
 ===================================================================*/
 
 #include "mitkFiberBundleTrackVisReader.h"
 #include <itkMetaDataObject.h>
 #include <vtkPolyData.h>
 #include <vtkDataReader.h>
 #include <vtkPolyDataReader.h>
 #include <vtkMatrix4x4.h>
 #include <vtkPolyLine.h>
 #include <vtkCellArray.h>
 #include <vtkDataArray.h>
 #include <vtkFloatArray.h>
 #include <vtkCellData.h>
 #include <vtkPointData.h>
 #include <itksys/SystemTools.hxx>
 #include <tinyxml.h>
 #include <vtkCleanPolyData.h>
 #include <mitkTrackvis.h>
 #include <mitkCustomMimeType.h>
 #include "mitkDiffusionIOMimeTypes.h"
 
 
 mitk::FiberBundleTrackVisReader::FiberBundleTrackVisReader()
-    : mitk::AbstractFileReader( mitk::DiffusionIOMimeTypes::FIBERBUNDLE_TRK_MIMETYPE_NAME(), "TrackVis Fiber Bundle Reader" )
+  : mitk::AbstractFileReader( mitk::DiffusionIOMimeTypes::FIBERBUNDLE_TRK_MIMETYPE_NAME(), "TrackVis Fiber Bundle Reader" )
 {
-    m_ServiceReg = this->RegisterService();
+  m_ServiceReg = this->RegisterService();
 }
 
 mitk::FiberBundleTrackVisReader::FiberBundleTrackVisReader(const FiberBundleTrackVisReader &other)
-    :mitk::AbstractFileReader(other)
+  :mitk::AbstractFileReader(other)
 {
 }
 
 mitk::FiberBundleTrackVisReader * mitk::FiberBundleTrackVisReader::Clone() const
 {
-    return new FiberBundleTrackVisReader(*this);
+  return new FiberBundleTrackVisReader(*this);
 }
 
 std::vector<itk::SmartPointer<mitk::BaseData> > mitk::FiberBundleTrackVisReader::Read()
 {
 
-    std::vector<itk::SmartPointer<mitk::BaseData> > result;
-    try
-    {
-        const std::string& locale = "C";
-        const std::string& currLocale = setlocale( LC_ALL, nullptr );
-        setlocale(LC_ALL, locale.c_str());
-
-        std::string filename = this->GetInputLocation();
-
-        std::string ext = itksys::SystemTools::GetFilenameLastExtension(filename);
-        ext = itksys::SystemTools::LowerCase(ext);
-
-        if (ext==".trk")
-        {
-            FiberBundle::Pointer mitk_fib = FiberBundle::New();
-            TrackVisFiberReader reader;
-            reader.open(this->GetInputLocation().c_str());
-            reader.read(mitk_fib.GetPointer());
-            result.push_back(mitk_fib.GetPointer());
-            return result;
-        }
-
-        setlocale(LC_ALL, currLocale.c_str());
-        MITK_INFO << "Fiber bundle read";
-    }
-    catch(...)
+  std::vector<itk::SmartPointer<mitk::BaseData> > result;
+  try
+  {
+    const std::string& locale = "C";
+    const std::string& currLocale = setlocale( LC_ALL, nullptr );
+    setlocale(LC_ALL, locale.c_str());
+
+    std::string filename = this->GetInputLocation();
+    MITK_INFO << "Loading tractogram (TrackVis format): " << itksys::SystemTools::GetFilenameName(filename);
+
+    std::string ext = itksys::SystemTools::GetFilenameLastExtension(filename);
+    ext = itksys::SystemTools::LowerCase(ext);
+
+    if (ext==".trk")
     {
-        throw;
+      FiberBundle::Pointer mitk_fib = FiberBundle::New();
+      TrackVisFiberReader reader;
+      reader.open(this->GetInputLocation().c_str());
+      reader.read(mitk_fib.GetPointer());
+      result.push_back(mitk_fib.GetPointer());
+      return result;
     }
-    return result;
+
+    setlocale(LC_ALL, currLocale.c_str());
+    MITK_INFO << "Fiber bundle read";
+  }
+  catch(...)
+  {
+    throw;
+  }
+  return result;
 }
diff --git a/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleVtkReader.cpp b/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleVtkReader.cpp
index 81da34bea2..0b98c2ebb2 100644
--- a/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleVtkReader.cpp
+++ b/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleVtkReader.cpp
@@ -1,284 +1,284 @@
 /*===================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center,
 Division of Medical and Biological Informatics.
 All rights reserved.
 
 This software is distributed WITHOUT ANY WARRANTY; without
 even the implied warranty of MERCHANTABILITY or FITNESS FOR
 A PARTICULAR PURPOSE.
 
 See LICENSE.txt or http://www.mitk.org for details.
 
 ===================================================================*/
 
 #include "mitkFiberBundleVtkReader.h"
 #include <itkMetaDataObject.h>
 #include <vtkPolyData.h>
 #include <vtkDataReader.h>
 #include <vtkPolyDataReader.h>
 #include <vtkMatrix4x4.h>
 #include <vtkPolyLine.h>
 #include <vtkCellArray.h>
 #include <vtkDataArray.h>
 #include <vtkFloatArray.h>
 #include <vtkCellData.h>
 #include <vtkPointData.h>
 #include <itksys/SystemTools.hxx>
 #include <tinyxml.h>
 #include <vtkCleanPolyData.h>
 #include <mitkTrackvis.h>
 #include <mitkCustomMimeType.h>
 #include <vtkXMLPolyDataReader.h>
 #include <vtkXMLDataReader.h>
 #include "mitkDiffusionIOMimeTypes.h"
 
 
 mitk::FiberBundleVtkReader::FiberBundleVtkReader()
-    : mitk::AbstractFileReader( mitk::DiffusionIOMimeTypes::FIBERBUNDLE_VTK_MIMETYPE_NAME(), "VTK Fiber Bundle Reader" )
+  : mitk::AbstractFileReader( mitk::DiffusionIOMimeTypes::FIBERBUNDLE_VTK_MIMETYPE_NAME(), "VTK Fiber Bundle Reader" )
 {
-    m_ServiceReg = this->RegisterService();
+  m_ServiceReg = this->RegisterService();
 }
 
 mitk::FiberBundleVtkReader::FiberBundleVtkReader(const FiberBundleVtkReader &other)
-    :mitk::AbstractFileReader(other)
+  :mitk::AbstractFileReader(other)
 {
 }
 
 mitk::FiberBundleVtkReader * mitk::FiberBundleVtkReader::Clone() const
 {
-    return new FiberBundleVtkReader(*this);
+  return new FiberBundleVtkReader(*this);
 }
 
 
 std::vector<itk::SmartPointer<mitk::BaseData> > mitk::FiberBundleVtkReader::Read()
 {
 
-    std::vector<itk::SmartPointer<mitk::BaseData> > result;
+  std::vector<itk::SmartPointer<mitk::BaseData> > result;
 
-    const std::string& locale = "C";
-    const std::string& currLocale = setlocale( LC_ALL, nullptr );
-    setlocale(LC_ALL, locale.c_str());
+  const std::string& locale = "C";
+  const std::string& currLocale = setlocale( LC_ALL, nullptr );
+  setlocale(LC_ALL, locale.c_str());
 
-    std::string filename = this->GetInputLocation();
+  std::string filename = this->GetInputLocation();
 
-    std::string ext = itksys::SystemTools::GetFilenameLastExtension(filename);
-    ext = itksys::SystemTools::LowerCase(ext);
+  std::string ext = itksys::SystemTools::GetFilenameLastExtension(filename);
+  ext = itksys::SystemTools::LowerCase(ext);
 
-    try
+  try
+  {
+    MITK_INFO << "Loading tractogram (VTK format): " << itksys::SystemTools::GetFilenameName(filename);
+    vtkSmartPointer<vtkPolyDataReader> reader = vtkSmartPointer<vtkPolyDataReader>::New();
+    reader->SetFileName( this->GetInputLocation().c_str() );
+
+    if (reader->IsFilePolyData())
     {
-        MITK_INFO << "Trying to load fiber file as VTK format.";
-        vtkSmartPointer<vtkPolyDataReader> reader = vtkSmartPointer<vtkPolyDataReader>::New();
-        reader->SetFileName( this->GetInputLocation().c_str() );
+      reader->Update();
 
-        if (reader->IsFilePolyData())
-        {
-            reader->Update();
+      if ( reader->GetOutput() != nullptr )
+      {
+        vtkSmartPointer<vtkPolyData> fiberPolyData = reader->GetOutput();
+        FiberBundle::Pointer fiberBundle = FiberBundle::New(fiberPolyData);
 
-            if ( reader->GetOutput() != nullptr )
+        vtkSmartPointer<vtkFloatArray> weights = vtkFloatArray::SafeDownCast(fiberPolyData->GetCellData()->GetArray("FIBER_WEIGHTS"));
+        if (weights!=nullptr)
+        {
+          //                    float weight=0;
+          for (int i=0; i<weights->GetNumberOfValues(); i++)
+          {
+            if (weights->GetValue(i)<0.0)
             {
-                vtkSmartPointer<vtkPolyData> fiberPolyData = reader->GetOutput();
-                FiberBundle::Pointer fiberBundle = FiberBundle::New(fiberPolyData);
-
-                vtkSmartPointer<vtkFloatArray> weights = vtkFloatArray::SafeDownCast(fiberPolyData->GetCellData()->GetArray("FIBER_WEIGHTS"));
-                if (weights!=nullptr)
-                {
-//                    float weight=0;
-                    for (int i=0; i<weights->GetNumberOfValues(); i++)
-                    {
-                        if (weights->GetValue(i)<0.0)
-                        {
-                            MITK_ERROR << "Fiber weight<0 detected! Setting value to 0.";
-                            weights->SetValue(i,0);
-                        }
-                    }
-//                        if (!mitk::Equal(weights->GetValue(i),weight,0.00001))
-//                        {
-//                            MITK_INFO << "Weight: " << weights->GetValue(i);
-//                            weight = weights->GetValue(i);
-//                        }
-                    fiberBundle->SetFiberWeights(weights);
-                }
-
-                vtkSmartPointer<vtkUnsignedCharArray> fiberColors = vtkUnsignedCharArray::SafeDownCast(fiberPolyData->GetPointData()->GetArray("FIBER_COLORS"));
-                if (fiberColors!=nullptr)
-                    fiberBundle->SetFiberColors(fiberColors);
-
-                result.push_back(fiberBundle.GetPointer());
-                return result;
+              MITK_ERROR << "Fiber weight<0 detected! Setting value to 0.";
+              weights->SetValue(i,0);
             }
+          }
+          //                        if (!mitk::Equal(weights->GetValue(i),weight,0.00001))
+          //                        {
+          //                            MITK_INFO << "Weight: " << weights->GetValue(i);
+          //                            weight = weights->GetValue(i);
+          //                        }
+          fiberBundle->SetFiberWeights(weights);
         }
-        else
-            MITK_INFO << "File is not VTK format.";
+
+        vtkSmartPointer<vtkUnsignedCharArray> fiberColors = vtkUnsignedCharArray::SafeDownCast(fiberPolyData->GetPointData()->GetArray("FIBER_COLORS"));
+        if (fiberColors!=nullptr)
+          fiberBundle->SetFiberColors(fiberColors);
+
+        result.push_back(fiberBundle.GetPointer());
+        return result;
+      }
     }
-    catch(...)
+    else
+      MITK_INFO << "File is not VTK format.";
+  }
+  catch(...)
+  {
+    throw;
+  }
+
+  try
+  {
+    MITK_INFO << "Trying to load fiber file as VTP format.";
+    vtkSmartPointer<vtkXMLPolyDataReader> reader = vtkSmartPointer<vtkXMLPolyDataReader>::New();
+    reader->SetFileName( this->GetInputLocation().c_str() );
+
+    if ( reader->CanReadFile(this->GetInputLocation().c_str()) )
     {
-        throw;
-    }
+      reader->Update();
 
-    try
-    {
-        MITK_INFO << "Trying to load fiber file as VTP format.";
-        vtkSmartPointer<vtkXMLPolyDataReader> reader = vtkSmartPointer<vtkXMLPolyDataReader>::New();
-        reader->SetFileName( this->GetInputLocation().c_str() );
+      if ( reader->GetOutput() != nullptr )
+      {
+        vtkSmartPointer<vtkPolyData> fiberPolyData = reader->GetOutput();
+        FiberBundle::Pointer fiberBundle = FiberBundle::New(fiberPolyData);
 
-        if ( reader->CanReadFile(this->GetInputLocation().c_str()) )
-        {
-            reader->Update();
+        vtkSmartPointer<vtkFloatArray> weights = vtkFloatArray::SafeDownCast(fiberPolyData->GetCellData()->GetArray("FIBER_WEIGHTS"));
 
-            if ( reader->GetOutput() != nullptr )
-            {
-                vtkSmartPointer<vtkPolyData> fiberPolyData = reader->GetOutput();
-                FiberBundle::Pointer fiberBundle = FiberBundle::New(fiberPolyData);
-
-                vtkSmartPointer<vtkFloatArray> weights = vtkFloatArray::SafeDownCast(fiberPolyData->GetCellData()->GetArray("FIBER_WEIGHTS"));
-
-                if (weights!=nullptr)
-                {
-//                                float weight=0;
-//                                for (int i=0; i<weights->GetSize(); i++)
-//                                    if (!mitk::Equal(weights->GetValue(i),weight,0.00001))
-//                                    {
-//                                        MITK_INFO << "Weight: " << weights->GetValue(i);
-//                                        weight = weights->GetValue(i);
-//                                    }
-                    fiberBundle->SetFiberWeights(weights);
-                }
-
-                vtkSmartPointer<vtkUnsignedCharArray> fiberColors = vtkUnsignedCharArray::SafeDownCast(fiberPolyData->GetPointData()->GetArray("FIBER_COLORS"));
-                if (fiberColors!=nullptr)
-                    fiberBundle->SetFiberColors(fiberColors);
-
-                result.push_back(fiberBundle.GetPointer());
-                return result;
-            }
+        if (weights!=nullptr)
+        {
+          //                                float weight=0;
+          //                                for (int i=0; i<weights->GetSize(); i++)
+          //                                    if (!mitk::Equal(weights->GetValue(i),weight,0.00001))
+          //                                    {
+          //                                        MITK_INFO << "Weight: " << weights->GetValue(i);
+          //                                        weight = weights->GetValue(i);
+          //                                    }
+          fiberBundle->SetFiberWeights(weights);
         }
-        else
-            MITK_INFO << "File is not VTP format.";
-    }
-    catch(...)
-    {
-        throw;
-    }
 
-    try
+        vtkSmartPointer<vtkUnsignedCharArray> fiberColors = vtkUnsignedCharArray::SafeDownCast(fiberPolyData->GetPointData()->GetArray("FIBER_COLORS"));
+        if (fiberColors!=nullptr)
+          fiberBundle->SetFiberColors(fiberColors);
+
+        result.push_back(fiberBundle.GetPointer());
+        return result;
+      }
+    }
+    else
+      MITK_INFO << "File is not VTP format.";
+  }
+  catch(...)
+  {
+    throw;
+  }
+
+  try
+  {
+    MITK_INFO << "Trying to load fiber file as deprecated XML format.";
+    vtkSmartPointer<vtkPolyData> fiberPolyData = vtkSmartPointer<vtkPolyData>::New();
+    vtkSmartPointer<vtkCellArray> cellArray = vtkSmartPointer<vtkCellArray>::New();
+    vtkSmartPointer<vtkPoints>    points = vtkSmartPointer<vtkPoints>::New();
+    TiXmlDocument doc( this->GetInputLocation().c_str() );
+    if(doc.LoadFile())
     {
-        MITK_INFO << "Trying to load fiber file as deprecated XML format.";
-        vtkSmartPointer<vtkPolyData> fiberPolyData = vtkSmartPointer<vtkPolyData>::New();
-        vtkSmartPointer<vtkCellArray> cellArray = vtkSmartPointer<vtkCellArray>::New();
-        vtkSmartPointer<vtkPoints>    points = vtkSmartPointer<vtkPoints>::New();
-        TiXmlDocument doc( this->GetInputLocation().c_str() );
-        if(doc.LoadFile())
+      TiXmlHandle hDoc(&doc);
+      TiXmlElement* pElem;
+      TiXmlHandle hRoot(0);
+      pElem = hDoc.FirstChildElement().Element();
+      // save this for later
+      hRoot = TiXmlHandle(pElem);
+      pElem = hRoot.FirstChildElement("geometry").Element();
+      // read geometry
+      mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New();
+      // read origin
+      mitk::Point3D origin;
+      double temp = 0;
+      pElem->Attribute("origin_x", &temp);
+      origin[0] = temp;
+      pElem->Attribute("origin_y", &temp);
+      origin[1] = temp;
+      pElem->Attribute("origin_z", &temp);
+      origin[2] = temp;
+      geometry->SetOrigin(origin);
+      // read spacing
+      ScalarType spacing[3];
+      pElem->Attribute("spacing_x", &temp);
+      spacing[0] = temp;
+      pElem->Attribute("spacing_y", &temp);
+      spacing[1] = temp;
+      pElem->Attribute("spacing_z", &temp);
+      spacing[2] = temp;
+      geometry->SetSpacing(spacing);
+      // read transform
+      vtkMatrix4x4* m = vtkMatrix4x4::New();
+      pElem->Attribute("xx", &temp);
+      m->SetElement(0,0,temp);
+      pElem->Attribute("xy", &temp);
+      m->SetElement(1,0,temp);
+      pElem->Attribute("xz", &temp);
+      m->SetElement(2,0,temp);
+      pElem->Attribute("yx", &temp);
+      m->SetElement(0,1,temp);
+      pElem->Attribute("yy", &temp);
+      m->SetElement(1,1,temp);
+      pElem->Attribute("yz", &temp);
+      m->SetElement(2,1,temp);
+      pElem->Attribute("zx", &temp);
+      m->SetElement(0,2,temp);
+      pElem->Attribute("zy", &temp);
+      m->SetElement(1,2,temp);
+      pElem->Attribute("zz", &temp);
+      m->SetElement(2,2,temp);
+      m->SetElement(0,3,origin[0]);
+      m->SetElement(1,3,origin[1]);
+      m->SetElement(2,3,origin[2]);
+      m->SetElement(3,3,1);
+      geometry->SetIndexToWorldTransformByVtkMatrix(m);
+      // read bounds
+      float bounds[] = {0, 0, 0, 0, 0, 0};
+      pElem->Attribute("size_x", &temp);
+      bounds[1] = temp;
+      pElem->Attribute("size_y", &temp);
+      bounds[3] = temp;
+      pElem->Attribute("size_z", &temp);
+      bounds[5] = temp;
+      geometry->SetFloatBounds(bounds);
+      geometry->SetImageGeometry(true);
+      pElem = hRoot.FirstChildElement("fiber_bundle").FirstChild().Element();
+      for( ; pElem ; pElem=pElem->NextSiblingElement())
+      {
+        TiXmlElement* pElem2 = pElem->FirstChildElement();
+        vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New();
+        for( ; pElem2; pElem2=pElem2->NextSiblingElement())
         {
-            TiXmlHandle hDoc(&doc);
-            TiXmlElement* pElem;
-            TiXmlHandle hRoot(0);
-            pElem = hDoc.FirstChildElement().Element();
-            // save this for later
-            hRoot = TiXmlHandle(pElem);
-            pElem = hRoot.FirstChildElement("geometry").Element();
-            // read geometry
-            mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New();
-            // read origin
-            mitk::Point3D origin;
-            double temp = 0;
-            pElem->Attribute("origin_x", &temp);
-            origin[0] = temp;
-            pElem->Attribute("origin_y", &temp);
-            origin[1] = temp;
-            pElem->Attribute("origin_z", &temp);
-            origin[2] = temp;
-            geometry->SetOrigin(origin);
-            // read spacing
-            ScalarType spacing[3];
-            pElem->Attribute("spacing_x", &temp);
-            spacing[0] = temp;
-            pElem->Attribute("spacing_y", &temp);
-            spacing[1] = temp;
-            pElem->Attribute("spacing_z", &temp);
-            spacing[2] = temp;
-            geometry->SetSpacing(spacing);
-            // read transform
-            vtkMatrix4x4* m = vtkMatrix4x4::New();
-            pElem->Attribute("xx", &temp);
-            m->SetElement(0,0,temp);
-            pElem->Attribute("xy", &temp);
-            m->SetElement(1,0,temp);
-            pElem->Attribute("xz", &temp);
-            m->SetElement(2,0,temp);
-            pElem->Attribute("yx", &temp);
-            m->SetElement(0,1,temp);
-            pElem->Attribute("yy", &temp);
-            m->SetElement(1,1,temp);
-            pElem->Attribute("yz", &temp);
-            m->SetElement(2,1,temp);
-            pElem->Attribute("zx", &temp);
-            m->SetElement(0,2,temp);
-            pElem->Attribute("zy", &temp);
-            m->SetElement(1,2,temp);
-            pElem->Attribute("zz", &temp);
-            m->SetElement(2,2,temp);
-            m->SetElement(0,3,origin[0]);
-            m->SetElement(1,3,origin[1]);
-            m->SetElement(2,3,origin[2]);
-            m->SetElement(3,3,1);
-            geometry->SetIndexToWorldTransformByVtkMatrix(m);
-            // read bounds
-            float bounds[] = {0, 0, 0, 0, 0, 0};
-            pElem->Attribute("size_x", &temp);
-            bounds[1] = temp;
-            pElem->Attribute("size_y", &temp);
-            bounds[3] = temp;
-            pElem->Attribute("size_z", &temp);
-            bounds[5] = temp;
-            geometry->SetFloatBounds(bounds);
-            geometry->SetImageGeometry(true);
-            pElem = hRoot.FirstChildElement("fiber_bundle").FirstChild().Element();
-            for( ; pElem ; pElem=pElem->NextSiblingElement())
-            {
-                TiXmlElement* pElem2 = pElem->FirstChildElement();
-                vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New();
-                for( ; pElem2; pElem2=pElem2->NextSiblingElement())
-                {
-                    Point3D point;
-                    pElem2->Attribute("pos_x", &temp);
-                    point[0] = temp;
-                    pElem2->Attribute("pos_y", &temp);
-                    point[1] = temp;
-                    pElem2->Attribute("pos_z", &temp);
-                    point[2] = temp;
-                    geometry->IndexToWorld(point, point);
-                    vtkIdType id = points->InsertNextPoint(point.GetDataPointer());
-                    container->GetPointIds()->InsertNextId(id);
-                }
-                cellArray->InsertNextCell(container);
-            }
-            fiberPolyData->SetPoints(points);
-            fiberPolyData->SetLines(cellArray);
-            vtkSmartPointer<vtkCleanPolyData> cleaner = vtkSmartPointer<vtkCleanPolyData>::New();
-            cleaner->SetInputData(fiberPolyData);
-            cleaner->Update();
-            fiberPolyData = cleaner->GetOutput();
-            FiberBundle::Pointer image = FiberBundle::New(fiberPolyData);
-            result.push_back(image.GetPointer());
-            return result;
-        }
-        else
-        {
-            MITK_INFO << "File is not deprectaed XML format.";
+          Point3D point;
+          pElem2->Attribute("pos_x", &temp);
+          point[0] = temp;
+          pElem2->Attribute("pos_y", &temp);
+          point[1] = temp;
+          pElem2->Attribute("pos_z", &temp);
+          point[2] = temp;
+          geometry->IndexToWorld(point, point);
+          vtkIdType id = points->InsertNextPoint(point.GetDataPointer());
+          container->GetPointIds()->InsertNextId(id);
         }
-
-        setlocale(LC_ALL, currLocale.c_str());
-        MITK_INFO << "Fiber bundle read";
+        cellArray->InsertNextCell(container);
+      }
+      fiberPolyData->SetPoints(points);
+      fiberPolyData->SetLines(cellArray);
+      vtkSmartPointer<vtkCleanPolyData> cleaner = vtkSmartPointer<vtkCleanPolyData>::New();
+      cleaner->SetInputData(fiberPolyData);
+      cleaner->Update();
+      fiberPolyData = cleaner->GetOutput();
+      FiberBundle::Pointer image = FiberBundle::New(fiberPolyData);
+      result.push_back(image.GetPointer());
+      return result;
     }
-    catch(...)
+    else
     {
-        throw;
+      MITK_INFO << "File is not deprectaed XML format.";
     }
 
-    throw "Selected file is no vtk readable fiber format (binary or ascii vtk or vtp file).";
+    setlocale(LC_ALL, currLocale.c_str());
+    MITK_INFO << "Fiber bundle read";
+  }
+  catch(...)
+  {
+    throw;
+  }
+
+  throw "Selected file is no vtk readable fiber format (binary or ascii vtk or vtp file).";
 
-    return result;
+  return result;
 }
diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFiberCurvatureFilter.h b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFiberCurvatureFilter.h
index a6b0c5cfa6..3101de522d 100644
--- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFiberCurvatureFilter.h
+++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFiberCurvatureFilter.h
@@ -1,83 +1,83 @@
 /*===================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center,
 Division of Medical and Biological Informatics.
 All rights reserved.
 
 This software is distributed WITHOUT ANY WARRANTY; without
 even the implied warranty of MERCHANTABILITY or FITNESS FOR
 A PARTICULAR PURPOSE.
 
 See LICENSE.txt or http://www.mitk.org for details.
 
 ===================================================================*/
 #ifndef itkFiberCurvatureFilter_h
 #define itkFiberCurvatureFilter_h
 
 // MITK
 #include <mitkPlanarEllipse.h>
 #include <mitkFiberBundle.h>
 #include <mitkFiberfoxParameters.h>
 
 // ITK
 #include <itkProcessObject.h>
 
 // VTK
 #include <vtkSmartPointer.h>
 #include <vtkPolyData.h>
 #include <vtkCellArray.h>
 #include <vtkPoints.h>
 #include <vtkPolyLine.h>
 
 using namespace std;
 
 namespace itk{
 
 /**
-* \brief Generates artificial fibers distributed in and interpolated between the input planar figures.   */
+* \brief    */
 
 class FiberCurvatureFilter : public ProcessObject
 {
 public:
 
     typedef FiberCurvatureFilter Self;
     typedef ProcessObject                                       Superclass;
     typedef SmartPointer< Self >                                Pointer;
     typedef SmartPointer< const Self >                          ConstPointer;
 
     itkFactorylessNewMacro(Self)
     itkCloneMacro(Self)
     itkTypeMacro( FiberCurvatureFilter, ProcessObject )
 
     virtual void Update() override{
         this->GenerateData();
     }
 
     itkSetMacro( Distance, double )
     itkSetMacro( AngularDeviation, double )
     itkSetMacro( RemoveFibers, bool )
     itkSetMacro( InputFiberBundle, FiberBundle::Pointer )
     itkGetMacro( OutputFiberBundle, FiberBundle::Pointer )
 
 protected:
 
     void GenerateData() override;
 
     FiberCurvatureFilter();
     virtual ~FiberCurvatureFilter();
 
     FiberBundle::Pointer m_InputFiberBundle;
     FiberBundle::Pointer m_OutputFiberBundle;
     double  m_AngularDeviation;
     double  m_Distance;
     bool    m_RemoveFibers;
 };
 }
 
 #ifndef ITK_MANUAL_INSTANTIATION
 #include "itkFiberCurvatureFilter.cpp"
 #endif
 
 #endif
diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFitFibersToImageFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFitFibersToImageFilter.cpp
index d9a719ec3d..0e143d3a09 100644
--- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFitFibersToImageFilter.cpp
+++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFitFibersToImageFilter.cpp
@@ -1,437 +1,459 @@
 #include "itkFitFibersToImageFilter.h"
 
 #include <boost/progress.hpp>
 
 namespace itk{
 
 FitFibersToImageFilter::FitFibersToImageFilter()
   : m_PeakImage(nullptr)
   , m_MaskImage(nullptr)
   , m_FitIndividualFibers(true)
   , m_GradientTolerance(1e-5)
   , m_Lambda(0.1)
   , m_MaxIterations(20)
   , m_FiberSampling(10)
   , m_Coverage(0)
   , m_Overshoot(0)
+  , m_RMSE(0.0)
   , m_FilterOutliers(true)
   , m_MeanWeight(1.0)
   , m_MedianWeight(1.0)
   , m_MinWeight(1.0)
   , m_MaxWeight(1.0)
   , m_Verbose(true)
   , m_DeepCopy(true)
+  , m_ResampleFibers(true)
   , m_NumUnknowns(0)
   , m_NumResiduals(0)
   , m_NumCoveredDirections(0)
 {
   this->SetNumberOfRequiredOutputs(3);
 }
 
 FitFibersToImageFilter::~FitFibersToImageFilter()
 {
 
 }
 
 void FitFibersToImageFilter::GenerateData()
 {
   int sz_x = m_PeakImage->GetLargestPossibleRegion().GetSize(0);
   int sz_y = m_PeakImage->GetLargestPossibleRegion().GetSize(1);
   int sz_z = m_PeakImage->GetLargestPossibleRegion().GetSize(2);
   int sz_peaks = m_PeakImage->GetLargestPossibleRegion().GetSize(3)/3 + 1; // +1 for zero - peak
   int num_voxels = sz_x*sz_y*sz_z;
 
   float minSpacing = 1;
   if(m_PeakImage->GetSpacing()[0]<m_PeakImage->GetSpacing()[1] && m_PeakImage->GetSpacing()[0]<m_PeakImage->GetSpacing()[2])
     minSpacing = m_PeakImage->GetSpacing()[0];
   else if (m_PeakImage->GetSpacing()[1] < m_PeakImage->GetSpacing()[2])
     minSpacing = m_PeakImage->GetSpacing()[1];
   else
     minSpacing = m_PeakImage->GetSpacing()[2];
 
   m_NumUnknowns = m_Tractograms.size();
   if (m_FitIndividualFibers)
   {
     m_NumUnknowns = 0;
     for (unsigned int bundle=0; bundle<m_Tractograms.size(); bundle++)
       m_NumUnknowns += m_Tractograms.at(bundle)->GetNumFibers();
   }
 
-  for (unsigned int bundle=0; bundle<m_Tractograms.size(); bundle++)
-  {
-    if (m_DeepCopy)
-      m_Tractograms[bundle] = m_Tractograms.at(bundle)->GetDeepCopy();
-    m_Tractograms.at(bundle)->ResampleLinear(minSpacing/m_FiberSampling);
-  }
+  if (m_ResampleFibers)
+    for (unsigned int bundle=0; bundle<m_Tractograms.size(); bundle++)
+    {
+      std::streambuf *old = cout.rdbuf(); // <-- save
+      std::stringstream ss;
+      std::cout.rdbuf (ss.rdbuf());
+      if (m_DeepCopy)
+        m_Tractograms[bundle] = m_Tractograms.at(bundle)->GetDeepCopy();
+      m_Tractograms.at(bundle)->ResampleLinear(minSpacing/m_FiberSampling);
+      std::cout.rdbuf (old);
+    }
 
   m_NumResiduals = num_voxels * sz_peaks;
 
   MITK_INFO << "Num. unknowns: " << m_NumUnknowns;
   MITK_INFO << "Num. residuals: " << m_NumResiduals;
   MITK_INFO << "Creating system ...";
 
   vnl_sparse_matrix<double> A;
   vnl_vector<double> b;
   A.set_size(m_NumResiduals, m_NumUnknowns);
   b.set_size(m_NumResiduals); b.fill(0.0);
 
   double TD = 0;
   double FD = 0;
   m_NumCoveredDirections = 0;
   unsigned int fiber_count = 0;
 
   for (unsigned int bundle=0; bundle<m_Tractograms.size(); bundle++)
   {
     vtkSmartPointer<vtkPolyData> polydata = m_Tractograms.at(bundle)->GetFiberPolyData();
 
     for (int i=0; i<m_Tractograms.at(bundle)->GetNumFibers(); ++i)
     {
       vtkCell* cell = polydata->GetCell(i);
       int numPoints = cell->GetNumberOfPoints();
       vtkPoints* points = cell->GetPoints();
 
       if (numPoints<2)
         MITK_INFO << "FIBER WITH ONLY ONE POINT ENCOUNTERED!";
 
       for (int j=0; j<numPoints-1; ++j)
       {
         double* p1 = points->GetPoint(j);
         PointType4 p;
         p[0]=p1[0];
         p[1]=p1[1];
         p[2]=p1[2];
         p[3]=0;
 
         itk::Index<4> idx4;
         m_PeakImage->TransformPhysicalPointToIndex(p, idx4);
         itk::Index<3> idx3; idx3[0] = idx4[0]; idx3[1] = idx4[1]; idx3[2] = idx4[2];
         if (!m_PeakImage->GetLargestPossibleRegion().IsInside(idx4) || (m_MaskImage.IsNotNull() && m_MaskImage->GetPixel(idx3)==0))
           continue;
 
         double* p2 = points->GetPoint(j+1);
         vnl_vector_fixed<float,3> fiber_dir;
         fiber_dir[0] = p[0]-p2[0];
         fiber_dir[1] = p[1]-p2[1];
         fiber_dir[2] = p[2]-p2[2];
         fiber_dir.normalize();
 
         double w = 1;
         int peak_id = sz_peaks-1;
         vnl_vector_fixed<float,3> odf_peak = GetClosestPeak(idx4, m_PeakImage, fiber_dir, peak_id, w);
         float peak_mag = odf_peak.magnitude();
 
         int x = idx4[0];
         int y = idx4[1];
         int z = idx4[2];
 
         unsigned int linear_index = x + sz_x*y + sz_x*sz_y*z + sz_x*sz_y*sz_z*peak_id;
 
         if (b[linear_index] == 0 && peak_id<3)
         {
           m_NumCoveredDirections++;
           FD += peak_mag;
         }
         TD += w;
 
         if (m_FitIndividualFibers)
         {
           b[linear_index] = peak_mag;
           A.put(linear_index, fiber_count, A.get(linear_index, fiber_count) + w);
         }
         else
         {
           b[linear_index] = peak_mag;
           A.put(linear_index, bundle, A.get(linear_index, bundle) + w);
         }
       }
 
       ++fiber_count;
     }
   }
 
   TD /= (m_NumCoveredDirections*fiber_count);
   FD /= m_NumCoveredDirections;
   A /= TD;
   b *= 100.0/FD;  // times 100 because we want to avoid too small values for computational reasons
 
   double init_lambda = fiber_count;  // initialization for lambda estimation
 
   itk::TimeProbe clock;
   clock.Start();
 
   VnlCostFunction cost(m_NumUnknowns);
   cost.SetProblem(A, b, init_lambda);
   m_Weights.set_size(m_NumUnknowns); // m_Weights.fill( TD/100.0 * FD/2.0 );
   m_Weights.fill( 0.0 );
   vnl_lbfgsb minimizer(cost);
   vnl_vector<double> l; l.set_size(m_NumUnknowns); l.fill(0);
   vnl_vector<long> bound_selection; bound_selection.set_size(m_NumUnknowns); bound_selection.fill(1);
   minimizer.set_bound_selection(bound_selection);
   minimizer.set_lower_bound(l);
   minimizer.set_projected_gradient_tolerance(m_GradientTolerance);
 
   MITK_INFO << "Estimating regularization";
   minimizer.set_trace(false);
   minimizer.set_max_function_evals(2);
   minimizer.minimize(m_Weights);
   vnl_vector<double> dx; dx.set_size(m_NumUnknowns); dx.fill(0.0);
   cost.grad_regu_localMSE(m_Weights, dx);
   double r = dx.magnitude()/m_Weights.magnitude();
   cost.m_Lambda *= m_Lambda*55.0/r;
   MITK_INFO << r << " - " << m_Lambda*55.0/r;
   if (cost.m_Lambda>10e7)
   {
     MITK_INFO << "Regularization estimation failed. Using default value.";
     cost.m_Lambda = fiber_count;
   }
   MITK_INFO << "Using regularization factor of " << cost.m_Lambda << " (λ: " << m_Lambda << ")";
 
   MITK_INFO << "Fitting fibers";
   minimizer.set_trace(m_Verbose);
 
   minimizer.set_max_function_evals(m_MaxIterations);
   minimizer.minimize(m_Weights);
 
   std::vector< double > weights;
   if (m_FilterOutliers)
   {
     for (auto w : m_Weights)
       weights.push_back(w);
     std::sort(weights.begin(), weights.end());
     MITK_INFO << "Setting upper weight bound to " << weights.at(m_NumUnknowns*0.99);
     vnl_vector<double> u; u.set_size(m_NumUnknowns); u.fill(weights.at(m_NumUnknowns*0.99));
     minimizer.set_upper_bound(u);
     bound_selection.fill(2);
     minimizer.set_bound_selection(bound_selection);
     minimizer.minimize(m_Weights);
     weights.clear();
   }
 
   for (auto w : m_Weights)
     weights.push_back(w);
   std::sort(weights.begin(), weights.end());
 
   m_MeanWeight = m_Weights.mean();
   m_MedianWeight = weights.at(m_NumUnknowns*0.5);
   m_MinWeight = weights.at(0);
   m_MaxWeight = weights.at(m_NumUnknowns-1);
 
   MITK_INFO << "*************************";
   MITK_INFO << "Weight statistics";
   MITK_INFO << "Mean: " << m_MeanWeight;
   MITK_INFO << "Median: " << m_MedianWeight;
   MITK_INFO << "75% quantile: " << weights.at(m_NumUnknowns*0.75);
   MITK_INFO << "95% quantile: " << weights.at(m_NumUnknowns*0.95);
   MITK_INFO << "99% quantile: " << weights.at(m_NumUnknowns*0.99);
   MITK_INFO << "Min: " << m_MinWeight;
   MITK_INFO << "Max: " << m_MaxWeight;
   MITK_INFO << "*************************";
   MITK_INFO << "NumEvals: " << minimizer.get_num_evaluations();
   MITK_INFO << "NumIterations: " << minimizer.get_num_iterations();
   MITK_INFO << "Residual cost: " << minimizer.get_end_error();
-  MITK_INFO << "Final RMS: " << cost.S->get_rms_error(m_Weights);
+  m_RMSE = cost.S->get_rms_error(m_Weights);
+  MITK_INFO << "Final RMS: " << m_RMSE;
 
   clock.Stop();
   int h = clock.GetTotal()/3600;
   int m = ((int)clock.GetTotal()%3600)/60;
   int s = (int)clock.GetTotal()%60;
   MITK_INFO << "Optimization took " << h << "h, " << m << "m and " << s << "s";
 
-  // transform back for peak image creation
-  A *= FD/100.0;
-  b *= FD/100.0;
-
   MITK_INFO << "Weighting fibers";
+  m_RmsDiffPerFiber.set_size(m_Weights.size());
+  m_RmsDiffPerBundle.set_size(m_Tractograms.size());
+  std::streambuf *old = cout.rdbuf(); // <-- save
+  std::stringstream ss;
+  std::cout.rdbuf (ss.rdbuf());
   if (m_FitIndividualFibers)
   {
     unsigned int fiber_count = 0;
     for (unsigned int bundle=0; bundle<m_Tractograms.size(); bundle++)
     {
+      vnl_vector< double > temp_weights;
+      temp_weights.set_size(m_Weights.size());
+      temp_weights.copy_in(m_Weights.data_block());
+
       for (int i=0; i<m_Tractograms.at(bundle)->GetNumFibers(); i++)
       {
         m_Tractograms.at(bundle)->SetFiberWeight(i, m_Weights[fiber_count]);
+        temp_weights[fiber_count] = 0;
+
         ++fiber_count;
       }
+      double d_rms = cost.S->get_rms_error(temp_weights) - m_RMSE;
+      m_RmsDiffPerBundle[bundle] = d_rms;
       m_Tractograms.at(bundle)->Compress(0.1);
       m_Tractograms.at(bundle)->ColorFibersByFiberWeights(false, true);
     }
   }
   else
   {
     for (unsigned int i=0; i<m_Tractograms.size(); ++i)
     {
       m_Tractograms.at(i)->SetFiberWeights(m_Weights[i]);
       m_Tractograms.at(i)->Compress(0.1);
       m_Tractograms.at(i)->ColorFibersByFiberWeights(false, true);
     }
   }
+  std::cout.rdbuf (old);
+
+  // transform back for peak image creation
+  A *= FD/100.0;
+  b *= FD/100.0;
 
   MITK_INFO << "Generating output images ...";
 
   itk::ImageDuplicator< PeakImgType >::Pointer duplicator = itk::ImageDuplicator< PeakImgType >::New();
   duplicator->SetInputImage(m_PeakImage);
   duplicator->Update();
   m_UnderexplainedImage = duplicator->GetOutput();
   m_UnderexplainedImage->FillBuffer(0.0);
 
   duplicator->SetInputImage(m_UnderexplainedImage);
   duplicator->Update();
   m_OverexplainedImage = duplicator->GetOutput();
   m_OverexplainedImage->FillBuffer(0.0);
 
   duplicator->SetInputImage(m_OverexplainedImage);
   duplicator->Update();
   m_ResidualImage = duplicator->GetOutput();
   m_ResidualImage->FillBuffer(0.0);
 
   duplicator->SetInputImage(m_ResidualImage);
   duplicator->Update();
   m_FittedImage = duplicator->GetOutput();
   m_FittedImage->FillBuffer(0.0);
 
   vnl_vector<double> fitted_b; fitted_b.set_size(b.size());
   cost.S->multiply(m_Weights, fitted_b);
 
   for (unsigned int r=0; r<b.size(); r++)
   {
     itk::Index<4> idx4;
     unsigned int linear_index = r;
     idx4[0] = linear_index % sz_x; linear_index /= sz_x;
     idx4[1] = linear_index % sz_y; linear_index /= sz_y;
     idx4[2] = linear_index % sz_z; linear_index /= sz_z;
     int peak_id = linear_index % sz_peaks;
 
     if (peak_id<sz_peaks-1)
     {
       vnl_vector_fixed<float,3> peak_dir;
 
       idx4[3] = peak_id*3;
       peak_dir[0] = m_PeakImage->GetPixel(idx4);
       idx4[3] += 1;
       peak_dir[1] = m_PeakImage->GetPixel(idx4);
       idx4[3] += 1;
       peak_dir[2] = m_PeakImage->GetPixel(idx4);
 
       peak_dir.normalize();
       peak_dir *= fitted_b[r];
 
       idx4[3] = peak_id*3;
       m_FittedImage->SetPixel(idx4, peak_dir[0]);
 
       idx4[3] += 1;
       m_FittedImage->SetPixel(idx4, peak_dir[1]);
 
       idx4[3] += 1;
       m_FittedImage->SetPixel(idx4, peak_dir[2]);
     }
   }
 
   FD = 0;
   m_Coverage = 0;
   m_Overshoot = 0;
 
   itk::Index<4> idx4;
   for (idx4[0]=0; idx4[0]<sz_x; ++idx4[0])
     for (idx4[1]=0; idx4[1]<sz_y; ++idx4[1])
       for (idx4[2]=0; idx4[2]<sz_z; ++idx4[2])
       {
         itk::Index<3> idx3; idx3[0] = idx4[0]; idx3[1] = idx4[1]; idx3[2] = idx4[2];
         if (m_MaskImage.IsNotNull() && m_MaskImage->GetPixel(idx3)==0)
           continue;
 
         vnl_vector_fixed<float,3> peak_dir;
         vnl_vector_fixed<float,3> fitted_dir;
         vnl_vector_fixed<float,3> overshoot_dir;
         for (idx4[3]=0; idx4[3]<(itk::IndexValueType)m_PeakImage->GetLargestPossibleRegion().GetSize(3); ++idx4[3])
         {
           peak_dir[idx4[3]%3] = m_PeakImage->GetPixel(idx4);
           fitted_dir[idx4[3]%3] = m_FittedImage->GetPixel(idx4);
           m_ResidualImage->SetPixel(idx4, m_PeakImage->GetPixel(idx4) - m_FittedImage->GetPixel(idx4));
 
           if (idx4[3]%3==2)
           {
             FD += peak_dir.magnitude();
 
             itk::Index<4> tidx= idx4;
             if (peak_dir.magnitude()>fitted_dir.magnitude())
             {
               m_Coverage += fitted_dir.magnitude();
               m_UnderexplainedImage->SetPixel(tidx, peak_dir[2]-fitted_dir[2]); tidx[3]--;
               m_UnderexplainedImage->SetPixel(tidx, peak_dir[1]-fitted_dir[1]); tidx[3]--;
               m_UnderexplainedImage->SetPixel(tidx, peak_dir[0]-fitted_dir[0]);
             }
             else
             {
               overshoot_dir[0] = fitted_dir[0]-peak_dir[0];
               overshoot_dir[1] = fitted_dir[1]-peak_dir[1];
               overshoot_dir[2] = fitted_dir[2]-peak_dir[2];
               m_Coverage += peak_dir.magnitude();
               m_Overshoot += overshoot_dir.magnitude();
               m_OverexplainedImage->SetPixel(tidx, overshoot_dir[2]); tidx[3]--;
               m_OverexplainedImage->SetPixel(tidx, overshoot_dir[1]); tidx[3]--;
               m_OverexplainedImage->SetPixel(tidx, overshoot_dir[0]);
             }
           }
         }
       }
 
   m_Coverage = m_Coverage/FD;
   m_Overshoot = m_Overshoot/FD;
 
-  MITK_INFO << std::fixed << "Coverage: " << setprecision(1) << 100.0*m_Coverage << "%";
-  MITK_INFO << std::fixed << "Overshoot: " << setprecision(1) << 100.0*m_Overshoot << "%";
+  MITK_INFO << std::fixed << "Coverage: " << setprecision(2) << 100.0*m_Coverage << "%";
+  MITK_INFO << std::fixed << "Overshoot: " << setprecision(2) << 100.0*m_Overshoot << "%";
 }
 
 vnl_vector_fixed<float,3> FitFibersToImageFilter::GetClosestPeak(itk::Index<4> idx, PeakImgType::Pointer peak_image , vnl_vector_fixed<float,3> fiber_dir, int& id, double& w )
 {
   int m_NumDirs = peak_image->GetLargestPossibleRegion().GetSize()[3]/3;
   vnl_vector_fixed<float,3> out_dir; out_dir.fill(0);
-  float angle = 0.8;
+  float angle = 0.9;
 
   for (int i=0; i<m_NumDirs; i++)
   {
     vnl_vector_fixed<float,3> dir;
     idx[3] = i*3;
     dir[0] = peak_image->GetPixel(idx);
     idx[3] += 1;
     dir[1] = peak_image->GetPixel(idx);
     idx[3] += 1;
     dir[2] = peak_image->GetPixel(idx);
 
     float mag = dir.magnitude();
     if (mag<mitk::eps)
       continue;
 
     dir.normalize();
 
     float a = dot_product(dir, fiber_dir);
     if (fabs(a)>angle)
     {
       angle = fabs(a);
       w = angle;
       if (a<0)
         out_dir = -dir;
       else
         out_dir = dir;
       out_dir *= mag;
       id = i;
     }
   }
 
   return out_dir;
 }
 
 std::vector<mitk::FiberBundle::Pointer> FitFibersToImageFilter::GetTractograms() const
 {
   return m_Tractograms;
 }
 
 void FitFibersToImageFilter::SetTractograms(const std::vector<mitk::FiberBundle::Pointer> &tractograms)
 {
   m_Tractograms = tractograms;
 }
 
 }
 
 
 
diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFitFibersToImageFilter.h b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFitFibersToImageFilter.h
index 119d39e57d..5907d9e874 100644
--- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFitFibersToImageFilter.h
+++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFitFibersToImageFilter.h
@@ -1,262 +1,271 @@
 #ifndef __itkFitFibersToImageFilter_h__
 #define __itkFitFibersToImageFilter_h__
 
 // MITK
 #include <mitkFiberBundle.h>
 #include <itkImageSource.h>
 #include <mitkPeakImage.h>
 #include <vnl/algo/vnl_lbfgsb.h>
 #include <vnl/vnl_sparse_matrix.h>
 #include <vnl/vnl_sparse_matrix_linear_system.h>
 #include <itkImageDuplicator.h>
 #include <itkTimeProbe.h>
 #include <itkMersenneTwisterRandomVariateGenerator.h>
 
 namespace itk{
 
 /**
 * \brief Fits the tractogram to the input peak image by assigning a weight to each fiber (similar to https://doi.org/10.1016/j.neuroimage.2015.06.092).  */
 
 class FitFibersToImageFilter : public ImageSource< mitk::PeakImage::ItkPeakImageType >
 {
 
 public:
 
   typedef FitFibersToImageFilter Self;
   typedef ProcessObject Superclass;
   typedef SmartPointer< Self > Pointer;
   typedef SmartPointer< const Self > ConstPointer;
 
   typedef itk::Point<float, 4> PointType4;
   typedef mitk::PeakImage::ItkPeakImageType       PeakImgType;
   typedef itk::Image<unsigned char, 3>            UcharImgType;
 
   itkFactorylessNewMacro(Self)
   itkCloneMacro(Self)
   itkTypeMacro( FitFibersToImageFilter, ImageSource )
 
   itkSetMacro( PeakImage, PeakImgType::Pointer)
   itkGetMacro( PeakImage, PeakImgType::Pointer)
   itkSetMacro( MaskImage, UcharImgType::Pointer)
   itkGetMacro( MaskImage, UcharImgType::Pointer)
   itkSetMacro( FitIndividualFibers, bool)
   itkGetMacro( FitIndividualFibers, bool)
   itkSetMacro( GradientTolerance, double)
   itkGetMacro( GradientTolerance, double)
   itkSetMacro( Lambda, double)
   itkGetMacro( Lambda, double)
   itkSetMacro( MaxIterations, int)
   itkGetMacro( MaxIterations, int)
   itkSetMacro( FiberSampling, float)
   itkGetMacro( FiberSampling, float)
   itkSetMacro( FilterOutliers, bool)
   itkGetMacro( FilterOutliers, bool)
   itkSetMacro( Verbose, bool)
   itkGetMacro( Verbose, bool)
   itkSetMacro( DeepCopy, bool)
   itkGetMacro( DeepCopy, bool)
+  itkSetMacro( ResampleFibers, bool)
+  itkGetMacro( ResampleFibers, bool)
 
   itkGetMacro( Weights, vnl_vector<double>)
+  itkGetMacro( RmsDiffPerBundle, vnl_vector<double>)
+  itkGetMacro( RmsDiffPerFiber, vnl_vector<double>)
   itkGetMacro( FittedImage, PeakImgType::Pointer)
   itkGetMacro( ResidualImage, PeakImgType::Pointer)
   itkGetMacro( OverexplainedImage, PeakImgType::Pointer)
   itkGetMacro( UnderexplainedImage, PeakImgType::Pointer)
   itkGetMacro( Coverage, double)
   itkGetMacro( Overshoot, double)
+  itkGetMacro( RMSE, double)
   itkGetMacro( MeanWeight, double)
   itkGetMacro( MedianWeight, double)
   itkGetMacro( MinWeight, double)
   itkGetMacro( MaxWeight, double)
   itkGetMacro( NumUnknowns, unsigned int)
   itkGetMacro( NumResiduals, unsigned int)
   itkGetMacro( NumCoveredDirections, unsigned int)
 
   void SetTractograms(const std::vector<mitk::FiberBundle::Pointer> &tractograms);
 
   void GenerateData() override;
 
   std::vector<mitk::FiberBundle::Pointer> GetTractograms() const;
 
 protected:
 
   FitFibersToImageFilter();
   virtual ~FitFibersToImageFilter();
 
   vnl_vector_fixed<float,3> GetClosestPeak(itk::Index<4> idx, PeakImgType::Pointer m_PeakImage , vnl_vector_fixed<float,3> fiber_dir, int& id, double& w );
 
   std::vector< mitk::FiberBundle::Pointer >   m_Tractograms;
   PeakImgType::Pointer                        m_PeakImage;
   UcharImgType::Pointer                       m_MaskImage;
   bool                                        m_FitIndividualFibers;
   double                                      m_GradientTolerance;
   double                                      m_Lambda;
   int                                         m_MaxIterations;
   float                                       m_FiberSampling;
   double                                      m_Coverage;
   double                                      m_Overshoot;
+  double                                      m_RMSE;
   bool                                        m_FilterOutliers;
   double                                      m_MeanWeight;
   double                                      m_MedianWeight;
   double                                      m_MinWeight;
   double                                      m_MaxWeight;
   bool                                        m_Verbose;
   bool                                        m_DeepCopy;
+  bool                                        m_ResampleFibers;
   unsigned int                                m_NumUnknowns;
   unsigned int                                m_NumResiduals;
   unsigned int                                m_NumCoveredDirections;
 
   // output
+  vnl_vector<double>                          m_RmsDiffPerBundle;
   vnl_vector<double>                          m_Weights;
+  vnl_vector<double>                          m_RmsDiffPerFiber;
   PeakImgType::Pointer                        m_UnderexplainedImage;
   PeakImgType::Pointer                        m_OverexplainedImage;
   PeakImgType::Pointer                        m_ResidualImage;
   PeakImgType::Pointer                        m_FittedImage;
 };
 
 }
 
 
 class VnlCostFunction : public vnl_cost_function
 {
 public:
 
   vnl_sparse_matrix_linear_system< double >* S;
   vnl_sparse_matrix< double > m_A;
   vnl_sparse_matrix< double > m_A_Ones; // matrix indicating active weights with 1
   vnl_vector< double > m_b;
   double m_Lambda;  // regularization factor
 
   vnl_vector<double> row_sums;  // number of active weights per row
   vnl_vector<double> local_weight_means;  // mean weight of each row
 
   void SetProblem(vnl_sparse_matrix< double >& A, vnl_vector<double>& b, double lambda)
   {
     S = new vnl_sparse_matrix_linear_system<double>(A, b);
     m_A = A;
     m_b = b;
     m_Lambda = lambda;
 
     m_A_Ones.set_size(m_A.rows(), m_A.cols());
     m_A.reset();
     while (m_A.next())
       m_A_Ones.put(m_A.getrow(), m_A.getcolumn(), 1);
 
     unsigned int N = m_b.size();
     vnl_vector<double> ones; ones.set_size(dim); ones.fill(1.0);
     row_sums.set_size(N);
     m_A_Ones.mult(ones, row_sums);
     local_weight_means.set_size(N);
   }
 
   VnlCostFunction(const int NumVars) : vnl_cost_function(NumVars)
   {
   }
 
   void regu_MSE(vnl_vector<double> const &x, double& cost)
   {
     double mean = x.mean();
     vnl_vector<double> tx = x-mean;
     cost += m_Lambda*1e8*tx.squared_magnitude()/x.size();
   }
 
   void regu_MSM(vnl_vector<double> const &x, double& cost)
   {
     cost += m_Lambda*1e8*x.squared_magnitude()/x.size();
   }
 
   void regu_localMSE(vnl_vector<double> const &x, double& cost)
   {
     m_A_Ones.mult(x, local_weight_means);
     local_weight_means = element_quotient(local_weight_means, row_sums);
 
     m_A_Ones.reset();
     double regu = 0;
     while (m_A_Ones.next())
     {
       double d = 0;
       if (x[m_A_Ones.getcolumn()]>local_weight_means[m_A_Ones.getrow()])
         d = std::exp(x[m_A_Ones.getcolumn()]) - std::exp(local_weight_means[m_A_Ones.getrow()]);
       else
         d = x[m_A_Ones.getcolumn()] - local_weight_means[m_A_Ones.getrow()];
       regu += d*d;
     }
     cost += m_Lambda*regu/dim;
   }
 
   void grad_regu_MSE(vnl_vector<double> const &x, vnl_vector<double> &dx)
   {
     double mean = x.mean();
     vnl_vector<double> tx = x-mean;
 
     vnl_vector<double> tx2(dim, 0.0);
     vnl_vector<double> h(dim, 1.0);
     for (int c=0; c<dim; c++)
     {
       h[c] = dim-1;
       tx2[c] += dot_product(h,tx);
       h[c] = 1;
     }
     dx += tx2*m_Lambda*1e8*2.0/(dim*dim);
 
   }
 
   void grad_regu_MSM(vnl_vector<double> const &x, vnl_vector<double> &dx)
   {
     dx += m_Lambda*1e8*2.0*x/dim;
   }
 
   void grad_regu_localMSE(vnl_vector<double> const &x, vnl_vector<double> &dx)
   {
     m_A_Ones.mult(x, local_weight_means);
     local_weight_means = element_quotient(local_weight_means, row_sums);
 
     vnl_vector<double> exp_x = x.apply(std::exp);
     vnl_vector<double> exp_means = local_weight_means.apply(std::exp);
 
     vnl_vector<double> tdx(dim, 0);
     m_A_Ones.reset();
     while (m_A_Ones.next())
     {
       int c = m_A_Ones.getcolumn();
       int r = m_A_Ones.getrow();
 
       if (x[c]>local_weight_means[r])
         tdx[c] += exp_x[c] * ( exp_x[c] - exp_means[r] );
       else
         tdx[c] += x[c] - local_weight_means[r];
     }
     dx += tdx*2.0*m_Lambda/dim;
   }
 
 
   double f(vnl_vector<double> const &x)
   {
     double cost = S->get_rms_error(x);
     cost *= cost;
 
     regu_localMSE(x, cost);
 
     return cost;
   }
 
   void gradf(vnl_vector<double> const &x, vnl_vector<double> &dx)
   {
     dx.fill(0.0);
     unsigned int N = m_b.size();
 
     vnl_vector<double> d; d.set_size(N);
     S->multiply(x,d);
     d -= m_b;
 
     S->transpose_multiply(d, dx);
     dx *= 2.0/N;
 
     grad_regu_localMSE(x,dx);
   }
 };
 
 #ifndef ITK_MANUAL_INSTANTIATION
 #include "itkFitFibersToImageFilter.cpp"
 #endif
 
 #endif // __itkFitFibersToImageFilter_h__
diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractDensityImageFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractDensityImageFilter.cpp
index 43076fa0b3..4aa60074cd 100644
--- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractDensityImageFilter.cpp
+++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractDensityImageFilter.cpp
@@ -1,251 +1,273 @@
 /*===================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Coindex[1]right (c) German Cancer Research Center,
 Division of Medical and Biological Informatics.
 All rights reserved.
 
 This software is distributed WITHOUT ANY WARRANTY; without
 even the implied warranty of MERCHANTABILITY or FITNESS FOR
 A PARTICULAR PURPOSE.
 
 See LICENSE.txt or http://www.mitk.org for details.
 
 ===================================================================*/
 #include "itkTractDensityImageFilter.h"
 
 // VTK
 #include <vtkPolyLine.h>
 #include <vtkCellArray.h>
 #include <vtkCellData.h>
 #include <vtkCell.h>
 
 // misc
 #include <math.h>
 #include <boost/progress.hpp>
 
 namespace itk{
 
 template< class OutputImageType >
 TractDensityImageFilter< OutputImageType >::TractDensityImageFilter()
-    : m_UpsamplingFactor(1)
-    , m_InvertImage(false)
-    , m_BinaryOutput(false)
-    , m_UseImageGeometry(false)
-    , m_OutputAbsoluteValues(false)
-    , m_UseTrilinearInterpolation(false)
-    , m_DoFiberResampling(true)
-    , m_WorkOnFiberCopy(true)
-    , m_MaxDensity(0)
+  : m_UpsamplingFactor(1)
+  , m_InvertImage(false)
+  , m_BinaryOutput(false)
+  , m_UseImageGeometry(false)
+  , m_OutputAbsoluteValues(false)
+  , m_UseTrilinearInterpolation(false)
+  , m_DoFiberResampling(true)
+  , m_WorkOnFiberCopy(true)
+  , m_MaxDensity(0)
+  , m_NumCoveredVoxels(0)
 {
 }
 
 template< class OutputImageType >
 TractDensityImageFilter< OutputImageType >::~TractDensityImageFilter()
 {
 }
 
 template< class OutputImageType >
 itk::Point<float, 3> TractDensityImageFilter< OutputImageType >::GetItkPoint(double point[3])
 {
-    itk::Point<float, 3> itkPoint;
-    itkPoint[0] = point[0];
-    itkPoint[1] = point[1];
-    itkPoint[2] = point[2];
-    return itkPoint;
+  itk::Point<float, 3> itkPoint;
+  itkPoint[0] = point[0];
+  itkPoint[1] = point[1];
+  itkPoint[2] = point[2];
+  return itkPoint;
 }
 
 template< class OutputImageType >
 void TractDensityImageFilter< OutputImageType >::GenerateData()
 {
-    // generate upsampled image
-    mitk::BaseGeometry::Pointer geometry = m_FiberBundle->GetGeometry();
-    typename OutputImageType::Pointer outImage = this->GetOutput();
-
-    // calculate new image parameters
-    itk::Vector<double,3> newSpacing;
-    mitk::Point3D newOrigin;
-    itk::Matrix<double, 3, 3> newDirection;
-    ImageRegion<3> upsampledRegion;
-    if (m_UseImageGeometry && !m_InputImage.IsNull())
+  // generate upsampled image
+  mitk::BaseGeometry::Pointer geometry = m_FiberBundle->GetGeometry();
+  typename OutputImageType::Pointer outImage = this->GetOutput();
+
+  // calculate new image parameters
+  itk::Vector<double,3> newSpacing;
+  mitk::Point3D newOrigin;
+  itk::Matrix<double, 3, 3> newDirection;
+  ImageRegion<3> upsampledRegion;
+  if (m_UseImageGeometry && !m_InputImage.IsNull())
+  {
+    MITK_INFO << "TractDensityImageFilter: using image geometry";
+    newSpacing = m_InputImage->GetSpacing()/m_UpsamplingFactor;
+    upsampledRegion = m_InputImage->GetLargestPossibleRegion();
+    newOrigin = m_InputImage->GetOrigin();
+    typename OutputImageType::RegionType::SizeType size = upsampledRegion.GetSize();
+    size[0] *= m_UpsamplingFactor;
+    size[1] *= m_UpsamplingFactor;
+    size[2] *= m_UpsamplingFactor;
+    upsampledRegion.SetSize(size);
+    newDirection = m_InputImage->GetDirection();
+  }
+  else
+  {
+    MITK_INFO << "TractDensityImageFilter: using fiber bundle geometry";
+    newSpacing = geometry->GetSpacing()/m_UpsamplingFactor;
+    newOrigin = geometry->GetOrigin();
+    mitk::Geometry3D::BoundsArrayType bounds = geometry->GetBounds();
+
+    // we retrieve the origin from a vtk-polydata (corner-based) and hance have to translate it to an image geometry
+    // i.e. center-based
+    newOrigin[0] += bounds.GetElement(0) + 0.5 * newSpacing[0];
+    newOrigin[1] += bounds.GetElement(2) + 0.5 * newSpacing[1];
+    newOrigin[2] += bounds.GetElement(4) + 0.5 * newSpacing[2];
+
+    for (int i=0; i<3; i++)
+      for (int j=0; j<3; j++)
+        newDirection[j][i] = geometry->GetMatrixColumn(i)[j];
+    upsampledRegion.SetSize(0, ceil( geometry->GetExtent(0)*m_UpsamplingFactor ) );
+    upsampledRegion.SetSize(1, ceil( geometry->GetExtent(1)*m_UpsamplingFactor ) );
+    upsampledRegion.SetSize(2, ceil( geometry->GetExtent(2)*m_UpsamplingFactor ) );
+  }
+  typename OutputImageType::RegionType::SizeType upsampledSize = upsampledRegion.GetSize();
+
+  // apply new image parameters
+  outImage->SetSpacing( newSpacing );
+  outImage->SetOrigin( newOrigin );
+  outImage->SetDirection( newDirection );
+  outImage->SetLargestPossibleRegion( upsampledRegion );
+  outImage->SetBufferedRegion( upsampledRegion );
+  outImage->SetRequestedRegion( upsampledRegion );
+  outImage->Allocate();
+  outImage->FillBuffer(0.0);
+
+  int w = upsampledSize[0];
+  int h = upsampledSize[1];
+  int d = upsampledSize[2];
+
+  // set/initialize output
+  OutPixelType* outImageBufferPointer = (OutPixelType*)outImage->GetBufferPointer();
+
+  // resample fiber bundle
+  float minSpacing = 1;
+  if(newSpacing[0]<newSpacing[1] && newSpacing[0]<newSpacing[2])
+    minSpacing = newSpacing[0];
+  else if (newSpacing[1] < newSpacing[2])
+    minSpacing = newSpacing[1];
+  else
+    minSpacing = newSpacing[2];
+
+  if (m_DoFiberResampling)
+  {
+    MITK_INFO << "TractDensityImageFilter: resampling fibers to ensure sufficient voxel coverage";
+    if (m_WorkOnFiberCopy)
+      m_FiberBundle = m_FiberBundle->GetDeepCopy();
+    m_FiberBundle->ResampleLinear(minSpacing/10);
+  }
+
+  MITK_INFO << "TractDensityImageFilter: starting image generation";
+
+  vtkSmartPointer<vtkPolyData> fiberPolyData = m_FiberBundle->GetFiberPolyData();
+
+  int numFibers = m_FiberBundle->GetNumFibers();
+  boost::progress_display disp(numFibers);
+  for( int i=0; i<numFibers; i++ )
+  {
+    ++disp;
+    vtkCell* cell = fiberPolyData->GetCell(i);
+    int numPoints = cell->GetNumberOfPoints();
+    vtkPoints* points = cell->GetPoints();
+
+    float weight = m_FiberBundle->GetFiberWeight(i);
+
+    // fill output image
+    for( int j=0; j<numPoints; j++)
     {
-        MITK_INFO << "TractDensityImageFilter: using image geometry";
-        newSpacing = m_InputImage->GetSpacing()/m_UpsamplingFactor;
-        upsampledRegion = m_InputImage->GetLargestPossibleRegion();
-        newOrigin = m_InputImage->GetOrigin();
-        typename OutputImageType::RegionType::SizeType size = upsampledRegion.GetSize();
-        size[0] *= m_UpsamplingFactor;
-        size[1] *= m_UpsamplingFactor;
-        size[2] *= m_UpsamplingFactor;
-        upsampledRegion.SetSize(size);
-        newDirection = m_InputImage->GetDirection();
+      itk::Point<float, 3> vertex = GetItkPoint(points->GetPoint(j));
+      itk::Index<3> index;
+      itk::ContinuousIndex<float, 3> contIndex;
+      outImage->TransformPhysicalPointToIndex(vertex, index);
+      outImage->TransformPhysicalPointToContinuousIndex(vertex, contIndex);
+
+      if (!m_UseTrilinearInterpolation && outImage->GetLargestPossibleRegion().IsInside(index))
+      {
+        if (outImage->GetPixel(index)==0)
+          m_NumCoveredVoxels++;
+
+        if (m_BinaryOutput)
+          outImage->SetPixel(index, 1);
+        else
+          outImage->SetPixel(index, outImage->GetPixel(index)+weight);
+        continue;
+      }
+
+      float frac_x = contIndex[0] - index[0];
+      float frac_y = contIndex[1] - index[1];
+      float frac_z = contIndex[2] - index[2];
+
+      if (frac_x<0)
+      {
+        index[0] -= 1;
+        frac_x += 1;
+      }
+      if (frac_y<0)
+      {
+        index[1] -= 1;
+        frac_y += 1;
+      }
+      if (frac_z<0)
+      {
+        index[2] -= 1;
+        frac_z += 1;
+      }
+
+      frac_x = 1-frac_x;
+      frac_y = 1-frac_y;
+      frac_z = 1-frac_z;
+
+      // int coordinates inside image?
+      if (index[0] < 0 || index[0] >= w-1)
+        continue;
+      if (index[1] < 0 || index[1] >= h-1)
+        continue;
+      if (index[2] < 0 || index[2] >= d-1)
+        continue;
+
+
+      if (outImageBufferPointer[( index[0]   + w*(index[1]  + h*index[2]  ))]==0)
+        m_NumCoveredVoxels++;
+      if (outImageBufferPointer[( index[0]   + w*(index[1]+1+ h*index[2]  ))]==0)
+        m_NumCoveredVoxels++;
+      if (outImageBufferPointer[( index[0]   + w*(index[1]  + h*index[2]+h))]==0)
+        m_NumCoveredVoxels++;
+      if (outImageBufferPointer[( index[0]   + w*(index[1]+1+ h*index[2]+h))]==0)
+        m_NumCoveredVoxels++;
+      if (outImageBufferPointer[( index[0]+1 + w*(index[1]  + h*index[2]  ))]==0)
+        m_NumCoveredVoxels++;
+      if (outImageBufferPointer[( index[0]+1 + w*(index[1]  + h*index[2]+h))]==0)
+        m_NumCoveredVoxels++;
+      if (outImageBufferPointer[( index[0]+1 + w*(index[1]+1+ h*index[2]  ))]==0)
+        m_NumCoveredVoxels++;
+      if (outImageBufferPointer[( index[0]+1 + w*(index[1]+1+ h*index[2]+h))]==0)
+        m_NumCoveredVoxels++;
+
+      if (m_BinaryOutput)
+      {
+        outImageBufferPointer[( index[0]   + w*(index[1]  + h*index[2]  ))] = 1;
+        outImageBufferPointer[( index[0]   + w*(index[1]+1+ h*index[2]  ))] = 1;
+        outImageBufferPointer[( index[0]   + w*(index[1]  + h*index[2]+h))] = 1;
+        outImageBufferPointer[( index[0]   + w*(index[1]+1+ h*index[2]+h))] = 1;
+        outImageBufferPointer[( index[0]+1 + w*(index[1]  + h*index[2]  ))] = 1;
+        outImageBufferPointer[( index[0]+1 + w*(index[1]  + h*index[2]+h))] = 1;
+        outImageBufferPointer[( index[0]+1 + w*(index[1]+1+ h*index[2]  ))] = 1;
+        outImageBufferPointer[( index[0]+1 + w*(index[1]+1+ h*index[2]+h))] = 1;
+      }
+      else
+      {
+        outImageBufferPointer[( index[0]   + w*(index[1]  + h*index[2]  ))] += (  frac_x)*(  frac_y)*(  frac_z);
+        outImageBufferPointer[( index[0]   + w*(index[1]+1+ h*index[2]  ))] += (  frac_x)*(1-frac_y)*(  frac_z);
+        outImageBufferPointer[( index[0]   + w*(index[1]  + h*index[2]+h))] += (  frac_x)*(  frac_y)*(1-frac_z);
+        outImageBufferPointer[( index[0]   + w*(index[1]+1+ h*index[2]+h))] += (  frac_x)*(1-frac_y)*(1-frac_z);
+        outImageBufferPointer[( index[0]+1 + w*(index[1]  + h*index[2]  ))] += (1-frac_x)*(  frac_y)*(  frac_z);
+        outImageBufferPointer[( index[0]+1 + w*(index[1]  + h*index[2]+h))] += (1-frac_x)*(  frac_y)*(1-frac_z);
+        outImageBufferPointer[( index[0]+1 + w*(index[1]+1+ h*index[2]  ))] += (1-frac_x)*(1-frac_y)*(  frac_z);
+        outImageBufferPointer[( index[0]+1 + w*(index[1]+1+ h*index[2]+h))] += (1-frac_x)*(1-frac_y)*(1-frac_z);
+      }
     }
-    else
-    {
-        MITK_INFO << "TractDensityImageFilter: using fiber bundle geometry";
-        newSpacing = geometry->GetSpacing()/m_UpsamplingFactor;
-        newOrigin = geometry->GetOrigin();
-        mitk::Geometry3D::BoundsArrayType bounds = geometry->GetBounds();
-
-        // we retrieve the origin from a vtk-polydata (corner-based) and hance have to translate it to an image geometry
-        // i.e. center-based
-        newOrigin[0] += bounds.GetElement(0) + 0.5 * newSpacing[0];
-        newOrigin[1] += bounds.GetElement(2) + 0.5 * newSpacing[1];
-        newOrigin[2] += bounds.GetElement(4) + 0.5 * newSpacing[2];
-
-        for (int i=0; i<3; i++)
-            for (int j=0; j<3; j++)
-                newDirection[j][i] = geometry->GetMatrixColumn(i)[j];
-        upsampledRegion.SetSize(0, ceil( geometry->GetExtent(0)*m_UpsamplingFactor ) );
-        upsampledRegion.SetSize(1, ceil( geometry->GetExtent(1)*m_UpsamplingFactor ) );
-        upsampledRegion.SetSize(2, ceil( geometry->GetExtent(2)*m_UpsamplingFactor ) );
-    }
-    typename OutputImageType::RegionType::SizeType upsampledSize = upsampledRegion.GetSize();
-
-    // apply new image parameters
-    outImage->SetSpacing( newSpacing );
-    outImage->SetOrigin( newOrigin );
-    outImage->SetDirection( newDirection );
-    outImage->SetLargestPossibleRegion( upsampledRegion );
-    outImage->SetBufferedRegion( upsampledRegion );
-    outImage->SetRequestedRegion( upsampledRegion );
-    outImage->Allocate();
-    outImage->FillBuffer(0.0);
-
-    int w = upsampledSize[0];
-    int h = upsampledSize[1];
-    int d = upsampledSize[2];
-
-    // set/initialize output
-    OutPixelType* outImageBufferPointer = (OutPixelType*)outImage->GetBufferPointer();
-
-    // resample fiber bundle
-    float minSpacing = 1;
-    if(newSpacing[0]<newSpacing[1] && newSpacing[0]<newSpacing[2])
-        minSpacing = newSpacing[0];
-    else if (newSpacing[1] < newSpacing[2])
-        minSpacing = newSpacing[1];
-    else
-        minSpacing = newSpacing[2];
-
-    if (m_DoFiberResampling)
-    {
-      MITK_INFO << "TractDensityImageFilter: resampling fibers to ensure sufficient voxel coverage";
-      if (m_WorkOnFiberCopy)
-        m_FiberBundle = m_FiberBundle->GetDeepCopy();
-      m_FiberBundle->ResampleLinear(minSpacing/10);
-    }
-
-    MITK_INFO << "TractDensityImageFilter: starting image generation";
-
-    vtkSmartPointer<vtkPolyData> fiberPolyData = m_FiberBundle->GetFiberPolyData();
-
-    int numFibers = m_FiberBundle->GetNumFibers();
-    boost::progress_display disp(numFibers);
-    for( int i=0; i<numFibers; i++ )
-    {
-        ++disp;
-        vtkCell* cell = fiberPolyData->GetCell(i);
-        int numPoints = cell->GetNumberOfPoints();
-        vtkPoints* points = cell->GetPoints();
-
-        float weight = m_FiberBundle->GetFiberWeight(i);
-
-        // fill output image
-        for( int j=0; j<numPoints; j++)
-        {
-            itk::Point<float, 3> vertex = GetItkPoint(points->GetPoint(j));
-            itk::Index<3> index;
-            itk::ContinuousIndex<float, 3> contIndex;
-            outImage->TransformPhysicalPointToIndex(vertex, index);
-            outImage->TransformPhysicalPointToContinuousIndex(vertex, contIndex);
-
-            if (!m_UseTrilinearInterpolation && outImage->GetLargestPossibleRegion().IsInside(index))
-            {
-                if (m_BinaryOutput)
-                    outImage->SetPixel(index, 1);
-                else
-                    outImage->SetPixel(index, outImage->GetPixel(index)+weight);
-                continue;
-            }
-
-            float frac_x = contIndex[0] - index[0];
-            float frac_y = contIndex[1] - index[1];
-            float frac_z = contIndex[2] - index[2];
-
-            if (frac_x<0)
-            {
-                index[0] -= 1;
-                frac_x += 1;
-            }
-            if (frac_y<0)
-            {
-                index[1] -= 1;
-                frac_y += 1;
-            }
-            if (frac_z<0)
-            {
-                index[2] -= 1;
-                frac_z += 1;
-            }
-
-            frac_x = 1-frac_x;
-            frac_y = 1-frac_y;
-            frac_z = 1-frac_z;
-
-            // int coordinates inside image?
-            if (index[0] < 0 || index[0] >= w-1)
-                continue;
-            if (index[1] < 0 || index[1] >= h-1)
-                continue;
-            if (index[2] < 0 || index[2] >= d-1)
-                continue;
-
-            if (m_BinaryOutput)
-            {
-                outImageBufferPointer[( index[0]   + w*(index[1]  + h*index[2]  ))] = 1;
-                outImageBufferPointer[( index[0]   + w*(index[1]+1+ h*index[2]  ))] = 1;
-                outImageBufferPointer[( index[0]   + w*(index[1]  + h*index[2]+h))] = 1;
-                outImageBufferPointer[( index[0]   + w*(index[1]+1+ h*index[2]+h))] = 1;
-                outImageBufferPointer[( index[0]+1 + w*(index[1]  + h*index[2]  ))] = 1;
-                outImageBufferPointer[( index[0]+1 + w*(index[1]  + h*index[2]+h))] = 1;
-                outImageBufferPointer[( index[0]+1 + w*(index[1]+1+ h*index[2]  ))] = 1;
-                outImageBufferPointer[( index[0]+1 + w*(index[1]+1+ h*index[2]+h))] = 1;
-            }
-            else
-            {
-                outImageBufferPointer[( index[0]   + w*(index[1]  + h*index[2]  ))] += (  frac_x)*(  frac_y)*(  frac_z);
-                outImageBufferPointer[( index[0]   + w*(index[1]+1+ h*index[2]  ))] += (  frac_x)*(1-frac_y)*(  frac_z);
-                outImageBufferPointer[( index[0]   + w*(index[1]  + h*index[2]+h))] += (  frac_x)*(  frac_y)*(1-frac_z);
-                outImageBufferPointer[( index[0]   + w*(index[1]+1+ h*index[2]+h))] += (  frac_x)*(1-frac_y)*(1-frac_z);
-                outImageBufferPointer[( index[0]+1 + w*(index[1]  + h*index[2]  ))] += (1-frac_x)*(  frac_y)*(  frac_z);
-                outImageBufferPointer[( index[0]+1 + w*(index[1]  + h*index[2]+h))] += (1-frac_x)*(  frac_y)*(1-frac_z);
-                outImageBufferPointer[( index[0]+1 + w*(index[1]+1+ h*index[2]  ))] += (1-frac_x)*(1-frac_y)*(  frac_z);
-                outImageBufferPointer[( index[0]+1 + w*(index[1]+1+ h*index[2]+h))] += (1-frac_x)*(1-frac_y)*(1-frac_z);
-            }
-        }
-    }
-
-    m_MaxDensity = 0;
+  }
+
+  m_MaxDensity = 0;
+  for (int i=0; i<w*h*d; i++)
+    if (m_MaxDensity < outImageBufferPointer[i])
+      m_MaxDensity = outImageBufferPointer[i];
+  if (!m_OutputAbsoluteValues && !m_BinaryOutput)
+  {
+    MITK_INFO << "TractDensityImageFilter: max-normalizing output image";
+    if (m_MaxDensity>0)
+      for (int i=0; i<w*h*d; i++)
+      {
+        outImageBufferPointer[i] /= m_MaxDensity;
+      }
+  }
+  if (m_InvertImage)
+  {
+    MITK_INFO << "TractDensityImageFilter: inverting image";
     for (int i=0; i<w*h*d; i++)
-        if (m_MaxDensity < outImageBufferPointer[i])
-            m_MaxDensity = outImageBufferPointer[i];
-    if (!m_OutputAbsoluteValues && !m_BinaryOutput)
-    {
-        MITK_INFO << "TractDensityImageFilter: max-normalizing output image";
-        if (m_MaxDensity>0)
-            for (int i=0; i<w*h*d; i++)
-            {
-                outImageBufferPointer[i] /= m_MaxDensity;
-            }
-    }
-    if (m_InvertImage)
-    {
-        MITK_INFO << "TractDensityImageFilter: inverting image";
-        for (int i=0; i<w*h*d; i++)
-            outImageBufferPointer[i] = 1-outImageBufferPointer[i];
-    }
-    MITK_INFO << "TractDensityImageFilter: finished processing";
+      outImageBufferPointer[i] = 1-outImageBufferPointer[i];
+  }
+  MITK_INFO << "TractDensityImageFilter: finished processing";
 }
 }
diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractDensityImageFilter.h b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractDensityImageFilter.h
index e302486857..e186a73433 100644
--- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractDensityImageFilter.h
+++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractDensityImageFilter.h
@@ -1,91 +1,93 @@
 /*===================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center,
 Division of Medical and Biological Informatics.
 All rights reserved.
 
 This software is distributed WITHOUT ANY WARRANTY; without
 even the implied warranty of MERCHANTABILITY or FITNESS FOR
 A PARTICULAR PURPOSE.
 
 See LICENSE.txt or http://www.mitk.org for details.
 
 ===================================================================*/
 #ifndef __itkTractDensityImageFilter_h__
 #define __itkTractDensityImageFilter_h__
 
 #include <itkImageSource.h>
 #include <itkImage.h>
 #include <itkVectorContainer.h>
 #include <itkRGBAPixel.h>
 #include <mitkFiberBundle.h>
 
 namespace itk{
 
 /**
 * \brief Generates tract density images from input fiberbundles (Calamante 2010).   */
 
 template< class OutputImageType >
 class TractDensityImageFilter : public ImageSource< OutputImageType >
 {
 
 public:
   typedef TractDensityImageFilter Self;
   typedef ProcessObject Superclass;
   typedef SmartPointer< Self > Pointer;
   typedef SmartPointer< const Self > ConstPointer;
 
   typedef typename OutputImageType::PixelType OutPixelType;
 
   itkFactorylessNewMacro(Self)
   itkCloneMacro(Self)
   itkTypeMacro( TractDensityImageFilter, ImageSource )
 
   itkSetMacro( UpsamplingFactor, float)                         ///< use higher resolution for ouput image
   itkGetMacro( UpsamplingFactor, float)                         ///< use higher resolution for ouput image
   itkSetMacro( InvertImage, bool)                               ///< voxelvalue = 1-voxelvalue
   itkGetMacro( InvertImage, bool)                               ///< voxelvalue = 1-voxelvalue
   itkSetMacro( BinaryOutput, bool)                              ///< generate binary fiber envelope
   itkGetMacro( BinaryOutput, bool)                              ///< generate binary fiber envelope
   itkSetMacro( OutputAbsoluteValues, bool)                      ///< output absolute values of the number of fibers per voxel
   itkGetMacro( OutputAbsoluteValues, bool)                      ///< output absolute values of the number of fibers per voxel
   itkSetMacro( UseImageGeometry, bool)                          ///< use input image geometry to initialize output image
   itkGetMacro( UseImageGeometry, bool)                          ///< use input image geometry to initialize output image
   itkSetMacro( FiberBundle, mitk::FiberBundle::Pointer)         ///< input fiber bundle
   itkSetMacro( InputImage, typename OutputImageType::Pointer)   ///< use input image geometry to initialize output image
   itkSetMacro( UseTrilinearInterpolation, bool )
   itkSetMacro( DoFiberResampling, bool )
   itkSetMacro( WorkOnFiberCopy, bool )
   itkGetMacro( MaxDensity, OutPixelType)
+  itkGetMacro( NumCoveredVoxels, unsigned int)
 
   void GenerateData();
 
 protected:
 
   itk::Point<float, 3> GetItkPoint(double point[3]);
 
   TractDensityImageFilter();
   virtual ~TractDensityImageFilter();
 
   typename OutputImageType::Pointer m_InputImage;           ///< use input image geometry to initialize output image
   mitk::FiberBundle::Pointer        m_FiberBundle;          ///< input fiber bundle
   float                             m_UpsamplingFactor;     ///< use higher resolution for ouput image
   bool                              m_InvertImage;          ///< voxelvalue = 1-voxelvalue
   bool                              m_BinaryOutput;         ///< generate binary fiber envelope
   bool                              m_UseImageGeometry;     ///< use input image geometry to initialize output image
   bool                              m_OutputAbsoluteValues; ///< do not normalize image values to 0-1
   bool                              m_UseTrilinearInterpolation;
   bool                              m_DoFiberResampling;
   bool                              m_WorkOnFiberCopy;
   OutPixelType                      m_MaxDensity;
+  unsigned int                      m_NumCoveredVoxels;
 };
 
 }
 
 #ifndef ITK_MANUAL_INSTANTIATION
 #include "itkTractDensityImageFilter.cpp"
 #endif
 
 #endif // __itkTractDensityImageFilter_h__
diff --git a/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.cpp b/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.cpp
index d33bf2cf32..fedc54a446 100755
--- a/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.cpp
+++ b/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.cpp
@@ -1,2335 +1,2588 @@
 /*===================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center,
 Division of Medical and Biological Informatics.
 All rights reserved.
 
 This software is distributed WITHOUT ANY WARRANTY; without
 even the implied warranty of MERCHANTABILITY or FITNESS FOR
 A PARTICULAR PURPOSE.
 
 See LICENSE.txt or http://www.mitk.org for details.
 
 ===================================================================*/
 
 
 #define _USE_MATH_DEFINES
 #include "mitkFiberBundle.h"
 
 #include <mitkPlanarCircle.h>
 #include <mitkPlanarPolygon.h>
 #include <mitkPlanarFigureComposite.h>
 #include "mitkImagePixelReadAccessor.h"
 #include <mitkPixelTypeMultiplex.h>
 
 #include <vtkPointData.h>
 #include <vtkDataArray.h>
 #include <vtkUnsignedCharArray.h>
 #include <vtkPolyLine.h>
 #include <vtkCellArray.h>
 #include <vtkCellData.h>
 #include <vtkIdFilter.h>
 #include <vtkClipPolyData.h>
 #include <vtkPlane.h>
 #include <vtkDoubleArray.h>
 #include <vtkKochanekSpline.h>
 #include <vtkParametricFunctionSource.h>
 #include <vtkParametricSpline.h>
 #include <vtkPolygon.h>
 #include <vtkCleanPolyData.h>
 #include <cmath>
 #include <boost/progress.hpp>
 #include <vtkTransformPolyDataFilter.h>
 #include <mitkTransferFunction.h>
 #include <vtkLookupTable.h>
 #include <mitkLookupTable.h>
 #include <vtkCardinalSpline.h>
+#include <vtkAppendPolyData.h>
 
 const char* mitk::FiberBundle::FIBER_ID_ARRAY = "Fiber_IDs";
 
 using namespace std;
 
 mitk::FiberBundle::FiberBundle( vtkPolyData* fiberPolyData )
   : m_NumFibers(0)
 {
   m_FiberWeights = vtkSmartPointer<vtkFloatArray>::New();
   m_FiberWeights->SetName("FIBER_WEIGHTS");
 
   m_FiberPolyData = vtkSmartPointer<vtkPolyData>::New();
   if (fiberPolyData != nullptr)
     m_FiberPolyData = fiberPolyData;
+  else
+  {
+    this->m_FiberPolyData->SetPoints(vtkSmartPointer<vtkPoints>::New());
+    this->m_FiberPolyData->SetLines(vtkSmartPointer<vtkCellArray>::New());
+  }
 
   this->UpdateFiberGeometry();
   this->GenerateFiberIds();
   this->ColorFibersByOrientation();
 }
 
 mitk::FiberBundle::~FiberBundle()
 {
 
 }
 
 mitk::FiberBundle::Pointer mitk::FiberBundle::GetDeepCopy()
 {
   mitk::FiberBundle::Pointer newFib = mitk::FiberBundle::New(m_FiberPolyData);
   newFib->SetFiberColors(this->m_FiberColors);
   newFib->SetFiberWeights(this->m_FiberWeights);
   return newFib;
 }
 
-vtkSmartPointer<vtkPolyData> mitk::FiberBundle::GeneratePolyDataByIds(std::vector<long> fiberIds)
+vtkSmartPointer<vtkPolyData> mitk::FiberBundle::GeneratePolyDataByIds(std::vector<long> fiberIds, vtkSmartPointer<vtkFloatArray> weights)
 {
   vtkSmartPointer<vtkPolyData> newFiberPolyData = vtkSmartPointer<vtkPolyData>::New();
   vtkSmartPointer<vtkCellArray> newLineSet = vtkSmartPointer<vtkCellArray>::New();
   vtkSmartPointer<vtkPoints> newPointSet = vtkSmartPointer<vtkPoints>::New();
+  weights->SetNumberOfValues(fiberIds.size());
 
+  int counter = 0;
   auto finIt = fiberIds.begin();
   while ( finIt != fiberIds.end() )
   {
     if (*finIt < 0 || *finIt>GetNumFibers()){
       MITK_INFO << "FiberID can not be negative or >NumFibers!!! check id Extraction!" << *finIt;
       break;
     }
 
     vtkSmartPointer<vtkCell> fiber = m_FiberIdDataSet->GetCell(*finIt);//->DeepCopy(fiber);
     vtkSmartPointer<vtkPoints> fibPoints = fiber->GetPoints();
     vtkSmartPointer<vtkPolyLine> newFiber = vtkSmartPointer<vtkPolyLine>::New();
     newFiber->GetPointIds()->SetNumberOfIds( fibPoints->GetNumberOfPoints() );
 
     for(int i=0; i<fibPoints->GetNumberOfPoints(); i++)
     {
       newFiber->GetPointIds()->SetId(i, newPointSet->GetNumberOfPoints());
       newPointSet->InsertNextPoint(fibPoints->GetPoint(i)[0], fibPoints->GetPoint(i)[1], fibPoints->GetPoint(i)[2]);
     }
 
+    weights->InsertValue(counter, this->GetFiberWeight(*finIt));
     newLineSet->InsertNextCell(newFiber);
     ++finIt;
+    ++counter;
   }
 
   newFiberPolyData->SetPoints(newPointSet);
   newFiberPolyData->SetLines(newLineSet);
   return newFiberPolyData;
 }
 
 // merge two fiber bundles
-mitk::FiberBundle::Pointer mitk::FiberBundle::AddBundle(mitk::FiberBundle* fib)
+mitk::FiberBundle::Pointer mitk::FiberBundle::AddBundles(std::vector< mitk::FiberBundle::Pointer > fibs)
 {
-  if (fib==nullptr)
+  vtkSmartPointer<vtkPolyData> vNewPolyData = vtkSmartPointer<vtkPolyData>::New();
+  vtkSmartPointer<vtkCellArray> vNewLines = vtkSmartPointer<vtkCellArray>::New();
+  vtkSmartPointer<vtkPoints> vNewPoints = vtkSmartPointer<vtkPoints>::New();
+
+  // add current fiber bundle
+  vtkSmartPointer<vtkFloatArray> weights = vtkSmartPointer<vtkFloatArray>::New();
+
+  int num_weights = this->GetNumFibers();
+  for (auto fib : fibs)
+    num_weights += fib->GetNumFibers();
+  weights->SetNumberOfValues(num_weights);
+
+  unsigned int counter = 0;
+  for (int i=0; i<m_FiberPolyData->GetNumberOfCells(); i++)
   {
-    MITK_WARN << "trying to call AddBundle with nullptr argument";
-    return nullptr;
+    vtkCell* cell = m_FiberPolyData->GetCell(i);
+    int numPoints = cell->GetNumberOfPoints();
+    vtkPoints* points = cell->GetPoints();
+
+    vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New();
+    for (int j=0; j<numPoints; j++)
+    {
+      double p[3];
+      points->GetPoint(j, p);
+
+      vtkIdType id = vNewPoints->InsertNextPoint(p);
+      container->GetPointIds()->InsertNextId(id);
+    }
+    weights->InsertValue(counter, this->GetFiberWeight(i));
+    vNewLines->InsertNextCell(container);
+    counter++;
   }
+
+  for (auto fib : fibs)
+  {
+    // add new fiber bundle
+    for (int i=0; i<fib->GetFiberPolyData()->GetNumberOfCells(); i++)
+    {
+      vtkCell* cell = fib->GetFiberPolyData()->GetCell(i);
+      int numPoints = cell->GetNumberOfPoints();
+      vtkPoints* points = cell->GetPoints();
+
+      vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New();
+      for (int j=0; j<numPoints; j++)
+      {
+        double p[3];
+        points->GetPoint(j, p);
+
+        vtkIdType id = vNewPoints->InsertNextPoint(p);
+        container->GetPointIds()->InsertNextId(id);
+      }
+      weights->InsertValue(counter, fib->GetFiberWeight(i));
+      vNewLines->InsertNextCell(container);
+      counter++;
+    }
+  }
+
+  // initialize PolyData
+  vNewPolyData->SetPoints(vNewPoints);
+  vNewPolyData->SetLines(vNewLines);
+
+  // initialize fiber bundle
+  mitk::FiberBundle::Pointer newFib = mitk::FiberBundle::New(vNewPolyData);
+  newFib->SetFiberWeights(weights);
+  return newFib;
+}
+
+// merge two fiber bundles
+mitk::FiberBundle::Pointer mitk::FiberBundle::AddBundle(mitk::FiberBundle* fib)
+{
+  if (fib==nullptr)
+    return this->GetDeepCopy();
+
   MITK_INFO << "Adding fibers";
 
   vtkSmartPointer<vtkPolyData> vNewPolyData = vtkSmartPointer<vtkPolyData>::New();
   vtkSmartPointer<vtkCellArray> vNewLines = vtkSmartPointer<vtkCellArray>::New();
   vtkSmartPointer<vtkPoints> vNewPoints = vtkSmartPointer<vtkPoints>::New();
 
   // add current fiber bundle
   vtkSmartPointer<vtkFloatArray> weights = vtkSmartPointer<vtkFloatArray>::New();
   weights->SetNumberOfValues(this->GetNumFibers()+fib->GetNumFibers());
 
   unsigned int counter = 0;
   for (int i=0; i<m_FiberPolyData->GetNumberOfCells(); i++)
   {
     vtkCell* cell = m_FiberPolyData->GetCell(i);
     int numPoints = cell->GetNumberOfPoints();
     vtkPoints* points = cell->GetPoints();
 
     vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New();
     for (int j=0; j<numPoints; j++)
     {
       double p[3];
       points->GetPoint(j, p);
 
       vtkIdType id = vNewPoints->InsertNextPoint(p);
       container->GetPointIds()->InsertNextId(id);
     }
     weights->InsertValue(counter, this->GetFiberWeight(i));
     vNewLines->InsertNextCell(container);
     counter++;
   }
 
   // add new fiber bundle
   for (int i=0; i<fib->GetFiberPolyData()->GetNumberOfCells(); i++)
   {
     vtkCell* cell = fib->GetFiberPolyData()->GetCell(i);
     int numPoints = cell->GetNumberOfPoints();
     vtkPoints* points = cell->GetPoints();
 
     vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New();
     for (int j=0; j<numPoints; j++)
     {
       double p[3];
       points->GetPoint(j, p);
 
       vtkIdType id = vNewPoints->InsertNextPoint(p);
       container->GetPointIds()->InsertNextId(id);
     }
     weights->InsertValue(counter, fib->GetFiberWeight(i));
     vNewLines->InsertNextCell(container);
     counter++;
   }
 
   // initialize PolyData
   vNewPolyData->SetPoints(vNewPoints);
   vNewPolyData->SetLines(vNewLines);
 
   // initialize fiber bundle
   mitk::FiberBundle::Pointer newFib = mitk::FiberBundle::New(vNewPolyData);
   newFib->SetFiberWeights(weights);
   return newFib;
 }
 
+// Only retain fibers with a weight larger than the specified threshold
+mitk::FiberBundle::Pointer mitk::FiberBundle::FilterByWeights(float weight_thr, bool invert)
+{
+  vtkSmartPointer<vtkPolyData> vNewPolyData = vtkSmartPointer<vtkPolyData>::New();
+  vtkSmartPointer<vtkCellArray> vNewLines = vtkSmartPointer<vtkCellArray>::New();
+  vtkSmartPointer<vtkPoints> vNewPoints = vtkSmartPointer<vtkPoints>::New();
+
+  std::vector<float> weights;
+
+  for (int i=0; i<this->GetNumFibers(); i++)
+  {
+    if ( (invert && this->GetFiberWeight(i)>weight_thr) || (!invert && this->GetFiberWeight(i)<=weight_thr))
+      continue;
+
+    vtkCell* cell = m_FiberPolyData->GetCell(i);
+    int numPoints = cell->GetNumberOfPoints();
+    vtkPoints* points = cell->GetPoints();
+
+    vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New();
+    for (int j=0; j<numPoints; j++)
+    {
+      double p[3];
+      points->GetPoint(j, p);
+
+      vtkIdType id = vNewPoints->InsertNextPoint(p);
+      container->GetPointIds()->InsertNextId(id);
+    }
+    vNewLines->InsertNextCell(container);
+    weights.push_back(this->GetFiberWeight(i));
+  }
+
+  // initialize PolyData
+  vNewPolyData->SetPoints(vNewPoints);
+  vNewPolyData->SetLines(vNewLines);
+
+  // initialize fiber bundle
+  mitk::FiberBundle::Pointer newFib = mitk::FiberBundle::New(vNewPolyData);
+  for (unsigned int i=0; i<weights.size(); ++i)
+    newFib->SetFiberWeight(i, weights.at(i));
+  return newFib;
+}
+
+// Only retain a subsample of the fibers
+mitk::FiberBundle::Pointer mitk::FiberBundle::SubsampleFibers(float factor)
+{
+  vtkSmartPointer<vtkPolyData> vNewPolyData = vtkSmartPointer<vtkPolyData>::New();
+  vtkSmartPointer<vtkCellArray> vNewLines = vtkSmartPointer<vtkCellArray>::New();
+  vtkSmartPointer<vtkPoints> vNewPoints = vtkSmartPointer<vtkPoints>::New();
+
+  int new_num_fibs = this->GetNumFibers()*factor;
+  MITK_INFO << "Subsampling fibers with factor " << factor << "(" << new_num_fibs << "/" << this->GetNumFibers() << ")";
+
+  // add current fiber bundle
+  vtkSmartPointer<vtkFloatArray> weights = vtkSmartPointer<vtkFloatArray>::New();
+  weights->SetNumberOfValues(new_num_fibs);
+
+  std::vector< int > ids;
+  for (int i=0; i<this->GetNumFibers(); i++)
+    ids.push_back(i);
+  std::random_shuffle(ids.begin(), ids.end());
+
+  unsigned int counter = 0;
+  for (int i=0; i<new_num_fibs; i++)
+  {
+    vtkCell* cell = m_FiberPolyData->GetCell(ids.at(i));
+    int numPoints = cell->GetNumberOfPoints();
+    vtkPoints* points = cell->GetPoints();
+
+    vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New();
+    for (int j=0; j<numPoints; j++)
+    {
+      double p[3];
+      points->GetPoint(j, p);
+
+      vtkIdType id = vNewPoints->InsertNextPoint(p);
+      container->GetPointIds()->InsertNextId(id);
+    }
+    weights->InsertValue(counter, this->GetFiberWeight(ids.at(i)));
+    vNewLines->InsertNextCell(container);
+    counter++;
+  }
+
+  // initialize PolyData
+  vNewPolyData->SetPoints(vNewPoints);
+  vNewPolyData->SetLines(vNewLines);
+
+  // initialize fiber bundle
+  mitk::FiberBundle::Pointer newFib = mitk::FiberBundle::New(vNewPolyData);
+  newFib->SetFiberWeights(weights);
+  return newFib;
+}
+
 // subtract two fiber bundles
 mitk::FiberBundle::Pointer mitk::FiberBundle::SubtractBundle(mitk::FiberBundle* fib)
 {
-  MITK_INFO << "Subtracting fibers";
+  if (fib==nullptr)
+    return this->GetDeepCopy();
 
+  MITK_INFO << "Subtracting fibers";
   vtkSmartPointer<vtkPolyData> vNewPolyData = vtkSmartPointer<vtkPolyData>::New();
   vtkSmartPointer<vtkCellArray> vNewLines = vtkSmartPointer<vtkCellArray>::New();
   vtkSmartPointer<vtkPoints> vNewPoints = vtkSmartPointer<vtkPoints>::New();
 
   std::vector< std::vector< itk::Point<float, 3> > > points1;
   for( int i=0; i<m_NumFibers; i++ )
   {
     vtkCell* cell = m_FiberPolyData->GetCell(i);
     int numPoints = cell->GetNumberOfPoints();
     vtkPoints* points = cell->GetPoints();
 
     if (points==nullptr || numPoints<=0)
       continue;
 
     itk::Point<float, 3> start = GetItkPoint(points->GetPoint(0));
     itk::Point<float, 3> end = GetItkPoint(points->GetPoint(numPoints-1));
 
     points1.push_back( {start, end} );
   }
 
   std::vector< std::vector< itk::Point<float, 3> > > points2;
   for( int i=0; i<fib->GetNumFibers(); i++ )
   {
     vtkCell* cell = fib->GetFiberPolyData()->GetCell(i);
     int numPoints = cell->GetNumberOfPoints();
     vtkPoints* points = cell->GetPoints();
 
     if (points==nullptr || numPoints<=0)
       continue;
 
     itk::Point<float, 3> start = GetItkPoint(points->GetPoint(0));
     itk::Point<float, 3> end = GetItkPoint(points->GetPoint(numPoints-1));
 
     points2.push_back( {start, end} );
   }
 
-  int progress = 0;
+//  int progress = 0;
   std::vector< int > ids;
 #pragma omp parallel for
   for (int i=0; i<(int)points1.size(); i++)
   {
-#pragma omp critical
-    {
-      progress++;
-      std::cout << (int)(100*(float)progress/points1.size()) << "%" << '\r';
-      cout.flush();
-    }
+//#pragma omp critical
+//    {
+//      progress++;
+//      std::cout << (int)(100*(float)progress/points1.size()) << "%" << '\r';
+//      cout.flush();
+//    }
 
     bool match = false;
     for (unsigned int j=0; j<points2.size(); j++)
     {
       auto v1 = points1.at(i);
       auto v2 = points2.at(j);
 
-      unsigned int matches = 0;
-      unsigned int reverse_matches = 0;
+      float dist=0;
+      for (unsigned int c=0; c<v1.size(); c++)
+      {
+        float d = v1[c][0]-v2[c][0];
+        dist += d*d;
+
+        d = v1[c][1]-v2[c][1];
+        dist += d*d;
+
+        d = v1[c][2]-v2[c][2];
+        dist += d*d;
+      }
+      dist /= v1.size();
+
+      if (dist<mitk::eps)
+      {
+        match = true;
+        break;
+      }
+
+      dist=0;
       for (unsigned int c=0; c<v1.size(); c++)
       {
-        if (v1[c].SquaredEuclideanDistanceTo(v2[c])<mitk::eps)
-          matches++;
-        if (v1[v1.size() - c - 1].SquaredEuclideanDistanceTo(v2[c])<mitk::eps)
-          reverse_matches++;
+        float d = v1[v1.size()-1-c][0]-v2[c][0];
+        dist += d*d;
+
+        d = v1[v1.size()-1-c][1]-v2[c][1];
+        dist += d*d;
+
+        d = v1[v1.size()-1-c][2]-v2[c][2];
+        dist += d*d;
       }
+      dist /= v1.size();
 
-      if (matches==v1.size() || reverse_matches==v1.size())
+      if (dist<mitk::eps)
       {
         match = true;
-        j=points2.size();
+        break;
       }
     }
 
 #pragma omp critical
     if (!match)
       ids.push_back(i);
   }
 
   for( int i : ids )
   {
     vtkCell* cell = m_FiberPolyData->GetCell(i);
     int numPoints = cell->GetNumberOfPoints();
     vtkPoints* points = cell->GetPoints();
 
     if (points==nullptr || numPoints<=0)
       continue;
 
     vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New();
     for( int j=0; j<numPoints; j++)
     {
       vtkIdType id = vNewPoints->InsertNextPoint(points->GetPoint(j));
       container->GetPointIds()->InsertNextId(id);
     }
     vNewLines->InsertNextCell(container);
   }
   if(vNewLines->GetNumberOfCells()==0)
-    return nullptr;
+    return mitk::FiberBundle::New();
   // initialize PolyData
   vNewPolyData->SetPoints(vNewPoints);
   vNewPolyData->SetLines(vNewLines);
 
   // initialize fiber bundle
   return mitk::FiberBundle::New(vNewPolyData);
 }
 
 itk::Point<float, 3> mitk::FiberBundle::GetItkPoint(double point[3])
 {
   itk::Point<float, 3> itkPoint;
   itkPoint[0] = point[0];
   itkPoint[1] = point[1];
   itkPoint[2] = point[2];
   return itkPoint;
 }
 
 /*
  * set PolyData (additional flag to recompute fiber geometry, default = true)
  */
 void mitk::FiberBundle::SetFiberPolyData(vtkSmartPointer<vtkPolyData> fiberPD, bool updateGeometry)
 {
   if (fiberPD == nullptr)
     this->m_FiberPolyData = vtkSmartPointer<vtkPolyData>::New();
   else
     m_FiberPolyData->DeepCopy(fiberPD);
 
   m_NumFibers = m_FiberPolyData->GetNumberOfLines();
 
   if (updateGeometry)
     UpdateFiberGeometry();
   GenerateFiberIds();
   ColorFibersByOrientation();
 }
 
 /*
  * return vtkPolyData
  */
 vtkSmartPointer<vtkPolyData> mitk::FiberBundle::GetFiberPolyData() const
 {
   return m_FiberPolyData;
 }
 
 void mitk::FiberBundle::ColorFibersByOrientation()
 {
   //===== FOR WRITING A TEST ========================
   //  colorT size == tupelComponents * tupelElements
   //  compare color results
   //  to cover this code 100% also PolyData needed, where colorarray already exists
   //  + one fiber with exactly 1 point
   //  + one fiber with 0 points
   //=================================================
 
   vtkPoints* extrPoints = nullptr;
   extrPoints = m_FiberPolyData->GetPoints();
   int numOfPoints = 0;
   if (extrPoints!=nullptr)
     numOfPoints = extrPoints->GetNumberOfPoints();
 
   //colors and alpha value for each single point, RGBA = 4 components
   unsigned char rgba[4] = {0,0,0,0};
   int componentSize = 4;
   m_FiberColors = vtkSmartPointer<vtkUnsignedCharArray>::New();
   m_FiberColors->Allocate(numOfPoints * componentSize);
   m_FiberColors->SetNumberOfComponents(componentSize);
   m_FiberColors->SetName("FIBER_COLORS");
 
   int numOfFibers = m_FiberPolyData->GetNumberOfLines();
   if (numOfFibers < 1)
     return;
 
   /* extract single fibers of fiberBundle */
   vtkCellArray* fiberList = m_FiberPolyData->GetLines();
   fiberList->InitTraversal();
   for (int fi=0; fi<numOfFibers; ++fi) {
 
     vtkIdType* idList; // contains the point id's of the line
     vtkIdType pointsPerFiber; // number of points for current line
     fiberList->GetNextCell(pointsPerFiber, idList);
 
     /* single fiber checkpoints: is number of points valid */
     if (pointsPerFiber > 1)
     {
       /* operate on points of single fiber */
       for (int i=0; i <pointsPerFiber; ++i)
       {
         /* process all points elastV[0]ept starting and endpoint for calculating color value take current point, previous point and next point */
         if (i<pointsPerFiber-1 && i > 0)
         {
           /* The color value of the current point is influenced by the previous point and next point. */
           vnl_vector_fixed< double, 3 > currentPntvtk(extrPoints->GetPoint(idList[i])[0], extrPoints->GetPoint(idList[i])[1],extrPoints->GetPoint(idList[i])[2]);
           vnl_vector_fixed< double, 3 > nextPntvtk(extrPoints->GetPoint(idList[i+1])[0], extrPoints->GetPoint(idList[i+1])[1], extrPoints->GetPoint(idList[i+1])[2]);
           vnl_vector_fixed< double, 3 > prevPntvtk(extrPoints->GetPoint(idList[i-1])[0], extrPoints->GetPoint(idList[i-1])[1], extrPoints->GetPoint(idList[i-1])[2]);
 
           vnl_vector_fixed< double, 3 > diff1;
           diff1 = currentPntvtk - nextPntvtk;
 
           vnl_vector_fixed< double, 3 > diff2;
           diff2 = currentPntvtk - prevPntvtk;
 
           vnl_vector_fixed< double, 3 > diff;
           diff = (diff1 - diff2) / 2.0;
           diff.normalize();
 
           rgba[0] = (unsigned char) (255.0 * std::fabs(diff[0]));
           rgba[1] = (unsigned char) (255.0 * std::fabs(diff[1]));
           rgba[2] = (unsigned char) (255.0 * std::fabs(diff[2]));
           rgba[3] = (unsigned char) (255.0);
         }
         else if (i==0)
         {
           /* First point has no previous point, therefore only diff1 is taken */
 
           vnl_vector_fixed< double, 3 > currentPntvtk(extrPoints->GetPoint(idList[i])[0], extrPoints->GetPoint(idList[i])[1],extrPoints->GetPoint(idList[i])[2]);
           vnl_vector_fixed< double, 3 > nextPntvtk(extrPoints->GetPoint(idList[i+1])[0], extrPoints->GetPoint(idList[i+1])[1], extrPoints->GetPoint(idList[i+1])[2]);
 
           vnl_vector_fixed< double, 3 > diff1;
           diff1 = currentPntvtk - nextPntvtk;
           diff1.normalize();
 
           rgba[0] = (unsigned char) (255.0 * std::fabs(diff1[0]));
           rgba[1] = (unsigned char) (255.0 * std::fabs(diff1[1]));
           rgba[2] = (unsigned char) (255.0 * std::fabs(diff1[2]));
           rgba[3] = (unsigned char) (255.0);
         }
         else if (i==pointsPerFiber-1)
         {
           /* Last point has no next point, therefore only diff2 is taken */
           vnl_vector_fixed< double, 3 > currentPntvtk(extrPoints->GetPoint(idList[i])[0], extrPoints->GetPoint(idList[i])[1],extrPoints->GetPoint(idList[i])[2]);
           vnl_vector_fixed< double, 3 > prevPntvtk(extrPoints->GetPoint(idList[i-1])[0], extrPoints->GetPoint(idList[i-1])[1], extrPoints->GetPoint(idList[i-1])[2]);
 
           vnl_vector_fixed< double, 3 > diff2;
           diff2 = currentPntvtk - prevPntvtk;
           diff2.normalize();
 
           rgba[0] = (unsigned char) (255.0 * std::fabs(diff2[0]));
           rgba[1] = (unsigned char) (255.0 * std::fabs(diff2[1]));
           rgba[2] = (unsigned char) (255.0 * std::fabs(diff2[2]));
           rgba[3] = (unsigned char) (255.0);
         }
         m_FiberColors->InsertTypedTuple(idList[i], rgba);
       }
     }
     else if (pointsPerFiber == 1)
     {
       /* a single point does not define a fiber (use vertex mechanisms instead */
       continue;
     }
     else
     {
       MITK_DEBUG << "Fiber with 0 points detected... please check your tractography algorithm!" ;
       continue;
     }
   }
   m_UpdateTime3D.Modified();
   m_UpdateTime2D.Modified();
 }
 
 void mitk::FiberBundle::ColorFibersByCurvature(bool, bool normalize)
 {
   double window = 5;
 
   //colors and alpha value for each single point, RGBA = 4 components
   unsigned char rgba[4] = {0,0,0,0};
   int componentSize = 4;
   m_FiberColors = vtkSmartPointer<vtkUnsignedCharArray>::New();
   m_FiberColors->Allocate(m_FiberPolyData->GetNumberOfPoints() * componentSize);
   m_FiberColors->SetNumberOfComponents(componentSize);
   m_FiberColors->SetName("FIBER_COLORS");
 
   mitk::LookupTable::Pointer mitkLookup = mitk::LookupTable::New();
   vtkSmartPointer<vtkLookupTable> lookupTable = vtkSmartPointer<vtkLookupTable>::New();
   lookupTable->SetTableRange(0.0, 0.8);
   lookupTable->Build();
   mitkLookup->SetVtkLookupTable(lookupTable);
   mitkLookup->SetType(mitk::LookupTable::JET);
 
   vector< double > values;
   double min = 1;
   double max = 0;
   MITK_INFO << "Coloring fibers by curvature";
   boost::progress_display disp(m_FiberPolyData->GetNumberOfCells());
   for (int i=0; i<m_FiberPolyData->GetNumberOfCells(); i++)
   {
     ++disp;
     vtkCell* cell = m_FiberPolyData->GetCell(i);
     int numPoints = cell->GetNumberOfPoints();
     vtkPoints* points = cell->GetPoints();
 
     // calculate curvatures
     for (int j=0; j<numPoints; j++)
     {
       double dist = 0;
       int c = j;
       std::vector< vnl_vector_fixed< float, 3 > > vectors;
       vnl_vector_fixed< float, 3 > meanV; meanV.fill(0.0);
       while(dist<window/2 && c>1)
       {
         double p1[3];
         points->GetPoint(c-1, p1);
         double p2[3];
         points->GetPoint(c, p2);
 
         vnl_vector_fixed< float, 3 > v;
         v[0] = p2[0]-p1[0];
         v[1] = p2[1]-p1[1];
         v[2] = p2[2]-p1[2];
         dist += v.magnitude();
         v.normalize();
         vectors.push_back(v);
         if (c==j)
           meanV += v;
         c--;
       }
       c = j;
       dist = 0;
       while(dist<window/2 && c<numPoints-1)
       {
         double p1[3];
         points->GetPoint(c, p1);
         double p2[3];
         points->GetPoint(c+1, p2);
 
         vnl_vector_fixed< float, 3 > v;
         v[0] = p2[0]-p1[0];
         v[1] = p2[1]-p1[1];
         v[2] = p2[2]-p1[2];
         dist += v.magnitude();
         v.normalize();
         vectors.push_back(v);
         if (c==j)
           meanV += v;
         c++;
       }
       meanV.normalize();
 
       double dev = 0;
       for (unsigned int c=0; c<vectors.size(); c++)
       {
         double angle = dot_product(meanV, vectors.at(c));
         if (angle>1.0)
           angle = 1.0;
         if (angle<-1.0)
           angle = -1.0;
         dev += acos(angle)*180/M_PI;
       }
       if (vectors.size()>0)
         dev /= vectors.size();
 
       dev = 1.0-dev/180.0;
       values.push_back(dev);
       if (dev<min)
         min = dev;
       if (dev>max)
         max = dev;
     }
   }
   unsigned int count = 0;
   for (int i=0; i<m_FiberPolyData->GetNumberOfCells(); i++)
   {
     vtkCell* cell = m_FiberPolyData->GetCell(i);
     int numPoints = cell->GetNumberOfPoints();
     for (int j=0; j<numPoints; j++)
     {
       double color[3];
       double dev = values.at(count);
       if (normalize)
         dev = (dev-min)/(max-min);
       else if (dev>1)
         dev = 1;
       lookupTable->GetColor(dev, color);
 
       rgba[0] = (unsigned char) (255.0 * color[0]);
       rgba[1] = (unsigned char) (255.0 * color[1]);
       rgba[2] = (unsigned char) (255.0 * color[2]);
       rgba[3] = (unsigned char) (255.0);
       m_FiberColors->InsertTypedTuple(cell->GetPointId(j), rgba);
       count++;
     }
   }
   m_UpdateTime3D.Modified();
   m_UpdateTime2D.Modified();
 }
 
 void mitk::FiberBundle::SetFiberOpacity(vtkDoubleArray* FAValArray)
 {
   for(long i=0; i<m_FiberColors->GetNumberOfTuples(); i++)
   {
     double faValue = FAValArray->GetValue(i);
     faValue = faValue * 255.0;
     m_FiberColors->SetComponent(i,3, (unsigned char) faValue );
   }
   m_UpdateTime3D.Modified();
   m_UpdateTime2D.Modified();
 }
 
 void mitk::FiberBundle::ResetFiberOpacity()
 {
   for(long i=0; i<m_FiberColors->GetNumberOfTuples(); i++)
     m_FiberColors->SetComponent(i,3, 255.0 );
   m_UpdateTime3D.Modified();
   m_UpdateTime2D.Modified();
 }
 
 void mitk::FiberBundle::ColorFibersByScalarMap(mitk::Image::Pointer FAimage, bool opacity, bool normalize)
 {
   mitkPixelTypeMultiplex3( ColorFibersByScalarMap, FAimage->GetPixelType(), FAimage, opacity, normalize );
   m_UpdateTime3D.Modified();
   m_UpdateTime2D.Modified();
 }
 
 template <typename TPixel>
 void mitk::FiberBundle::ColorFibersByScalarMap(const mitk::PixelType, mitk::Image::Pointer image, bool opacity, bool normalize)
 {
   m_FiberColors = vtkSmartPointer<vtkUnsignedCharArray>::New();
   m_FiberColors->Allocate(m_FiberPolyData->GetNumberOfPoints() * 4);
   m_FiberColors->SetNumberOfComponents(4);
   m_FiberColors->SetName("FIBER_COLORS");
 
   mitk::ImagePixelReadAccessor<TPixel,3> readimage(image, image->GetVolumeData(0));
 
   unsigned char rgba[4] = {0,0,0,0};
   vtkPoints* pointSet = m_FiberPolyData->GetPoints();
 
   mitk::LookupTable::Pointer mitkLookup = mitk::LookupTable::New();
   vtkSmartPointer<vtkLookupTable> lookupTable = vtkSmartPointer<vtkLookupTable>::New();
   lookupTable->SetTableRange(0.0, 0.8);
   lookupTable->Build();
   mitkLookup->SetVtkLookupTable(lookupTable);
   mitkLookup->SetType(mitk::LookupTable::JET);
 
   double min = 9999999;
   double max = -9999999;
   for(long i=0; i<m_FiberPolyData->GetNumberOfPoints(); ++i)
   {
     Point3D px;
     px[0] = pointSet->GetPoint(i)[0];
     px[1] = pointSet->GetPoint(i)[1];
     px[2] = pointSet->GetPoint(i)[2];
     double pixelValue = readimage.GetPixelByWorldCoordinates(px);
     if (pixelValue>max)
       max = pixelValue;
     if (pixelValue<min)
       min = pixelValue;
   }
 
   for(long i=0; i<m_FiberPolyData->GetNumberOfPoints(); ++i)
   {
     Point3D px;
     px[0] = pointSet->GetPoint(i)[0];
     px[1] = pointSet->GetPoint(i)[1];
     px[2] = pointSet->GetPoint(i)[2];
     double pixelValue = readimage.GetPixelByWorldCoordinates(px);
 
     if (normalize)
       pixelValue = (pixelValue-min)/(max-min);
     else if (pixelValue>1)
       pixelValue = 1;
 
     double color[3];
     lookupTable->GetColor(1-pixelValue, color);
 
     rgba[0] = (unsigned char) (255.0 * color[0]);
     rgba[1] = (unsigned char) (255.0 * color[1]);
     rgba[2] = (unsigned char) (255.0 * color[2]);
     if (opacity)
       rgba[3] = (unsigned char) (255.0 * pixelValue);
     else
       rgba[3] = (unsigned char) (255.0);
     m_FiberColors->InsertTypedTuple(i, rgba);
   }
   m_UpdateTime3D.Modified();
   m_UpdateTime2D.Modified();
 }
 
 
 void mitk::FiberBundle::ColorFibersByFiberWeights(bool opacity, bool normalize)
 {
   m_FiberColors = vtkSmartPointer<vtkUnsignedCharArray>::New();
   m_FiberColors->Allocate(m_FiberPolyData->GetNumberOfPoints() * 4);
   m_FiberColors->SetNumberOfComponents(4);
   m_FiberColors->SetName("FIBER_COLORS");
 
   mitk::LookupTable::Pointer mitkLookup = mitk::LookupTable::New();
   vtkSmartPointer<vtkLookupTable> lookupTable = vtkSmartPointer<vtkLookupTable>::New();
   lookupTable->SetTableRange(0.0, 0.8);
   lookupTable->Build();
   mitkLookup->SetVtkLookupTable(lookupTable);
   mitkLookup->SetType(mitk::LookupTable::JET);
 
   unsigned char rgba[4] = {0,0,0,0};
   unsigned int counter = 0;
 
   float max = -999999;
   float min = 999999;
   for (int i=0; i<m_NumFibers; i++)
   {
     double weight = this->GetFiberWeight(i);
     if (weight>max)
       max = weight;
     if (weight<min)
       min = weight;
   }
   if (fabs(max-min)<0.00001)
   {
     max = 1;
     min = 0;
   }
 
   for (int i=0; i<m_NumFibers; i++)
   {
     vtkCell* cell = m_FiberPolyData->GetCell(i);
     int numPoints = cell->GetNumberOfPoints();
     double weight = this->GetFiberWeight(i);
 
     for (int j=0; j<numPoints; j++)
     {
       float v = weight;
       if (normalize)
         v = (v-min)/(max-min);
       else if (v>1)
         v = 1;
       double color[3];
       lookupTable->GetColor(1-v, color);
 
       rgba[0] = (unsigned char) (255.0 * color[0]);
       rgba[1] = (unsigned char) (255.0 * color[1]);
       rgba[2] = (unsigned char) (255.0 * color[2]);
       if (opacity)
         rgba[3] = (unsigned char) (255.0 * v);
       else
         rgba[3] = (unsigned char) (255.0);
 
       m_FiberColors->InsertTypedTuple(counter, rgba);
       counter++;
     }
   }
 
   m_UpdateTime3D.Modified();
   m_UpdateTime2D.Modified();
 }
 
 void mitk::FiberBundle::SetFiberColors(float r, float g, float b, float alpha)
 {
   m_FiberColors = vtkSmartPointer<vtkUnsignedCharArray>::New();
   m_FiberColors->Allocate(m_FiberPolyData->GetNumberOfPoints() * 4);
   m_FiberColors->SetNumberOfComponents(4);
   m_FiberColors->SetName("FIBER_COLORS");
 
   unsigned char rgba[4] = {0,0,0,0};
   for(long i=0; i<m_FiberPolyData->GetNumberOfPoints(); ++i)
   {
     rgba[0] = (unsigned char) r;
     rgba[1] = (unsigned char) g;
     rgba[2] = (unsigned char) b;
     rgba[3] = (unsigned char) alpha;
     m_FiberColors->InsertTypedTuple(i, rgba);
   }
   m_UpdateTime3D.Modified();
   m_UpdateTime2D.Modified();
 }
 
 void mitk::FiberBundle::GenerateFiberIds()
 {
   if (m_FiberPolyData == nullptr)
     return;
 
   vtkSmartPointer<vtkIdFilter> idFiberFilter = vtkSmartPointer<vtkIdFilter>::New();
   idFiberFilter->SetInputData(m_FiberPolyData);
   idFiberFilter->CellIdsOn();
   //  idFiberFilter->PointIdsOn(); // point id's are not needed
   idFiberFilter->SetIdsArrayName(FIBER_ID_ARRAY);
   idFiberFilter->FieldDataOn();
   idFiberFilter->Update();
 
   m_FiberIdDataSet = idFiberFilter->GetOutput();
 
 }
 
+float mitk::FiberBundle::GetOverlap(ItkUcharImgType* mask, bool do_resampling)
+{
+  vtkSmartPointer<vtkPolyData> PolyData = m_FiberPolyData;
+  mitk::FiberBundle::Pointer fibCopy = this;
+  if (do_resampling)
+  {
+    float minSpacing = 1;
+    if(mask->GetSpacing()[0]<mask->GetSpacing()[1] && mask->GetSpacing()[0]<mask->GetSpacing()[2])
+      minSpacing = mask->GetSpacing()[0];
+    else if (mask->GetSpacing()[1] < mask->GetSpacing()[2])
+      minSpacing = mask->GetSpacing()[1];
+    else
+      minSpacing = mask->GetSpacing()[2];
+
+    fibCopy = this->GetDeepCopy();
+    fibCopy->ResampleLinear(minSpacing/5);
+    PolyData = fibCopy->GetFiberPolyData();
+  }
+
+  MITK_INFO << "Calculating overlap";
+  int inside = 0;
+  int outside = 0;
+  boost::progress_display disp(m_NumFibers);
+  for (int i=0; i<m_NumFibers; i++)
+  {
+    ++disp;
+    vtkCell* cell = PolyData->GetCell(i);
+    int numPoints = cell->GetNumberOfPoints();
+    vtkPoints* points = cell->GetPoints();
+
+    for (int j=0; j<numPoints; j++)
+    {
+      double* p = points->GetPoint(j);
+      itk::Point<float, 3> itkP;
+      itkP[0] = p[0]; itkP[1] = p[1]; itkP[2] = p[2];
+      itk::Index<3> idx;
+      mask->TransformPhysicalPointToIndex(itkP, idx);
+
+      if ( mask->GetLargestPossibleRegion().IsInside(idx) && mask->GetPixel(idx) != 0 )
+        inside++;
+      else
+        outside++;
+    }
+  }
+
+  if (inside+outside==0)
+    outside = 1;
+  return (float)inside/(inside+outside);
+}
+
 mitk::FiberBundle::Pointer mitk::FiberBundle::ExtractFiberSubset(ItkUcharImgType* mask, bool anyPoint, bool invert, bool bothEnds, float fraction, bool do_resampling)
 {
+  if (m_NumFibers==0 || mask==nullptr)
+    return mitk::FiberBundle::New(nullptr);
+
   vtkSmartPointer<vtkPolyData> PolyData = m_FiberPolyData;
   mitk::FiberBundle::Pointer fibCopy = this;
   if (anyPoint && do_resampling)
   {
     float minSpacing = 1;
     if(mask->GetSpacing()[0]<mask->GetSpacing()[1] && mask->GetSpacing()[0]<mask->GetSpacing()[2])
       minSpacing = mask->GetSpacing()[0];
     else if (mask->GetSpacing()[1] < mask->GetSpacing()[2])
       minSpacing = mask->GetSpacing()[1];
     else
       minSpacing = mask->GetSpacing()[2];
 
     fibCopy = this->GetDeepCopy();
     fibCopy->ResampleLinear(minSpacing/5);
     PolyData = fibCopy->GetFiberPolyData();
   }
   vtkSmartPointer<vtkPoints> vtkNewPoints = vtkSmartPointer<vtkPoints>::New();
   vtkSmartPointer<vtkCellArray> vtkNewCells = vtkSmartPointer<vtkCellArray>::New();
 
   std::vector< float > new_weights;
 
   MITK_INFO << "Extracting fibers with mask image";
   boost::progress_display disp(m_NumFibers);
   for (int i=0; i<m_NumFibers; i++)
   {
     ++disp;
 
     vtkCell* cell = PolyData->GetCell(i);
     int numPoints = cell->GetNumberOfPoints();
     vtkPoints* points = cell->GetPoints();
 
     vtkCell* cellOriginal = m_FiberPolyData->GetCell(i);
     int numPointsOriginal = cellOriginal->GetNumberOfPoints();
     vtkPoints* pointsOriginal = cellOriginal->GetPoints();
 
     vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New();
 
     if (numPoints>1 && numPointsOriginal)
     {
       if (anyPoint)
       {
         int inside = 0;
         int outside = 0;
         if (!invert)
         {
           for (int j=0; j<numPoints; j++)
           {
             double* p = points->GetPoint(j);
 
             itk::Point<float, 3> itkP;
             itkP[0] = p[0]; itkP[1] = p[1]; itkP[2] = p[2];
             itk::Index<3> idx;
             mask->TransformPhysicalPointToIndex(itkP, idx);
 
             if ( mask->GetLargestPossibleRegion().IsInside(idx) && mask->GetPixel(idx) != 0 )
             {
               inside++;
               if (fraction==0)
                 break;
             }
             else
               outside++;
           }
 
           float current_fraction = 0.0;
           if (inside+outside>0)
             current_fraction = (float)inside/(inside+outside);
 
           if (current_fraction>fraction)
           {
             for (int k=0; k<numPoints; k++)
             {
               double* p = points->GetPoint(k);
               vtkIdType id = vtkNewPoints->InsertNextPoint(p);
               container->GetPointIds()->InsertNextId(id);
             }
           }
         }
         else
         {
           bool includeFiber = true;
           for (int j=0; j<numPoints; j++)
           {
             double* p = points->GetPoint(j);
 
             itk::Point<float, 3> itkP;
             itkP[0] = p[0]; itkP[1] = p[1]; itkP[2] = p[2];
             itk::Index<3> idx;
             mask->TransformPhysicalPointToIndex(itkP, idx);
 
             if ( mask->GetPixel(idx) != 0 && mask->GetLargestPossibleRegion().IsInside(idx) )
             {
               inside++;
               includeFiber = false;
               break;
             }
             else
               outside++;
           }
           if (includeFiber)
           {
 
             for (int k=0; k<numPoints; k++)
             {
               double* p = points->GetPoint(k);
               vtkIdType id = vtkNewPoints->InsertNextPoint(p);
               container->GetPointIds()->InsertNextId(id);
             }
           }
         }
       }
       else
       {
         double* start = pointsOriginal->GetPoint(0);
         itk::Point<float, 3> itkStart;
         itkStart[0] = start[0]; itkStart[1] = start[1]; itkStart[2] = start[2];
         itk::Index<3> idxStart;
         mask->TransformPhysicalPointToIndex(itkStart, idxStart);
 
         double* end = pointsOriginal->GetPoint(numPointsOriginal-1);
         itk::Point<float, 3> itkEnd;
         itkEnd[0] = end[0]; itkEnd[1] = end[1]; itkEnd[2] = end[2];
         itk::Index<3> idxEnd;
         mask->TransformPhysicalPointToIndex(itkEnd, idxEnd);
 
         if (invert)
         {
           if (bothEnds)
           {
             if ( mask->GetPixel(idxStart) == 0 && mask->GetPixel(idxEnd) == 0 )
             {
               for (int j=0; j<numPointsOriginal; j++)
               {
                 double* p = pointsOriginal->GetPoint(j);
                 vtkIdType id = vtkNewPoints->InsertNextPoint(p);
                 container->GetPointIds()->InsertNextId(id);
               }
             }
           }
           else if ( mask->GetPixel(idxStart) == 0 || mask->GetPixel(idxEnd) == 0 )
           {
             for (int j=0; j<numPointsOriginal; j++)
             {
               double* p = pointsOriginal->GetPoint(j);
               vtkIdType id = vtkNewPoints->InsertNextPoint(p);
               container->GetPointIds()->InsertNextId(id);
             }
           }
         }
         else
         {
           if (bothEnds)
           {
             if ( mask->GetPixel(idxStart) != 0 && mask->GetPixel(idxEnd) != 0 && mask->GetLargestPossibleRegion().IsInside(idxStart) && mask->GetLargestPossibleRegion().IsInside(idxEnd) )
             {
               for (int j=0; j<numPointsOriginal; j++)
               {
                 double* p = pointsOriginal->GetPoint(j);
                 vtkIdType id = vtkNewPoints->InsertNextPoint(p);
                 container->GetPointIds()->InsertNextId(id);
               }
             }
           }
           else if ( (mask->GetPixel(idxStart) != 0 && mask->GetLargestPossibleRegion().IsInside(idxStart)) || (mask->GetPixel(idxEnd) != 0 && mask->GetLargestPossibleRegion().IsInside(idxEnd)) )
           {
             for (int j=0; j<numPointsOriginal; j++)
             {
               double* p = pointsOriginal->GetPoint(j);
               vtkIdType id = vtkNewPoints->InsertNextPoint(p);
               container->GetPointIds()->InsertNextId(id);
             }
           }
         }
       }
     }
 
     if (container->GetNumberOfPoints()>0)
     {
       new_weights.push_back(fibCopy->GetFiberWeight(i));
       vtkNewCells->InsertNextCell(container);
     }
   }
 
   if (vtkNewCells->GetNumberOfCells()<=0)
-    return nullptr;
+    return mitk::FiberBundle::New(nullptr);
 
   vtkSmartPointer<vtkPolyData> newPolyData = vtkSmartPointer<vtkPolyData>::New();
   newPolyData->SetPoints(vtkNewPoints);
   newPolyData->SetLines(vtkNewCells);
+
   mitk::FiberBundle::Pointer newfib = mitk::FiberBundle::New(newPolyData);
   for (unsigned int i=0; i<new_weights.size(); i++)
     newfib->SetFiberWeight(i, new_weights.at(i));
   return newfib;
 }
 
 mitk::FiberBundle::Pointer mitk::FiberBundle::RemoveFibersOutside(ItkUcharImgType* mask, bool invert)
 {
   float minSpacing = 1;
   if(mask->GetSpacing()[0]<mask->GetSpacing()[1] && mask->GetSpacing()[0]<mask->GetSpacing()[2])
     minSpacing = mask->GetSpacing()[0];
   else if (mask->GetSpacing()[1] < mask->GetSpacing()[2])
     minSpacing = mask->GetSpacing()[1];
   else
     minSpacing = mask->GetSpacing()[2];
 
   mitk::FiberBundle::Pointer fibCopy = this->GetDeepCopy();
   fibCopy->ResampleLinear(minSpacing/10);
   vtkSmartPointer<vtkPolyData> PolyData =fibCopy->GetFiberPolyData();
 
   vtkSmartPointer<vtkPoints> vtkNewPoints = vtkSmartPointer<vtkPoints>::New();
   vtkSmartPointer<vtkCellArray> vtkNewCells = vtkSmartPointer<vtkCellArray>::New();
 
   MITK_INFO << "Cutting fibers";
   boost::progress_display disp(m_NumFibers);
   for (int i=0; i<m_NumFibers; i++)
   {
     ++disp;
 
     vtkCell* cell = PolyData->GetCell(i);
     int numPoints = cell->GetNumberOfPoints();
     vtkPoints* points = cell->GetPoints();
 
     vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New();
     if (numPoints>1)
     {
       int newNumPoints = 0;
       for (int j=0; j<numPoints; j++)
       {
         double* p = points->GetPoint(j);
 
         itk::Point<float, 3> itkP;
         itkP[0] = p[0]; itkP[1] = p[1]; itkP[2] = p[2];
         itk::Index<3> idx;
         mask->TransformPhysicalPointToIndex(itkP, idx);
 
         if ( mask->GetPixel(idx) != 0 && mask->GetLargestPossibleRegion().IsInside(idx) && !invert )
         {
           vtkIdType id = vtkNewPoints->InsertNextPoint(p);
           container->GetPointIds()->InsertNextId(id);
           newNumPoints++;
         }
         else if ( (mask->GetPixel(idx) == 0 || !mask->GetLargestPossibleRegion().IsInside(idx)) && invert )
         {
           vtkIdType id = vtkNewPoints->InsertNextPoint(p);
           container->GetPointIds()->InsertNextId(id);
           newNumPoints++;
         }
         else if (newNumPoints>0)
         {
           vtkNewCells->InsertNextCell(container);
 
           newNumPoints = 0;
           container = vtkSmartPointer<vtkPolyLine>::New();
         }
       }
 
       if (newNumPoints>0)
         vtkNewCells->InsertNextCell(container);
     }
 
   }
 
   if (vtkNewCells->GetNumberOfCells()<=0)
     return nullptr;
 
   vtkSmartPointer<vtkPolyData> newPolyData = vtkSmartPointer<vtkPolyData>::New();
   newPolyData->SetPoints(vtkNewPoints);
   newPolyData->SetLines(vtkNewCells);
   mitk::FiberBundle::Pointer newFib = mitk::FiberBundle::New(newPolyData);
   newFib->Compress(0.1);
   return newFib;
 }
 
 mitk::FiberBundle::Pointer mitk::FiberBundle::ExtractFiberSubset(DataNode* roi, DataStorage* storage)
 {
   if (roi==nullptr || !(dynamic_cast<PlanarFigure*>(roi->GetData()) || dynamic_cast<PlanarFigureComposite*>(roi->GetData())) )
     return nullptr;
 
   std::vector<long> tmp = ExtractFiberIdSubset(roi, storage);
 
   if (tmp.size()<=0)
     return mitk::FiberBundle::New();
-  vtkSmartPointer<vtkPolyData> pTmp = GeneratePolyDataByIds(tmp);
-  return mitk::FiberBundle::New(pTmp);
+  vtkSmartPointer<vtkFloatArray> weights = vtkSmartPointer<vtkFloatArray>::New();
+  vtkSmartPointer<vtkPolyData> pTmp = GeneratePolyDataByIds(tmp, weights);
+  mitk::FiberBundle::Pointer fib = mitk::FiberBundle::New(pTmp);
+  fib->SetFiberWeights(weights);
+  return fib;
 }
 
 std::vector<long> mitk::FiberBundle::ExtractFiberIdSubset(DataNode *roi, DataStorage* storage)
 {
   std::vector<long> result;
   if (roi==nullptr || roi->GetData()==nullptr)
     return result;
 
   mitk::PlanarFigureComposite::Pointer pfc = dynamic_cast<mitk::PlanarFigureComposite*>(roi->GetData());
   if (!pfc.IsNull()) // handle composite
   {
     DataStorage::SetOfObjects::ConstPointer children = storage->GetDerivations(roi);
     if (children->size()==0)
       return result;
 
     switch (pfc->getOperationType())
     {
     case 0: // AND
     {
       MITK_INFO << "AND";
       result = this->ExtractFiberIdSubset(children->ElementAt(0), storage);
       std::vector<long>::iterator it;
       for (unsigned int i=1; i<children->Size(); ++i)
       {
         std::vector<long> inRoi = this->ExtractFiberIdSubset(children->ElementAt(i), storage);
 
         std::vector<long> rest(std::min(result.size(),inRoi.size()));
         it = std::set_intersection(result.begin(), result.end(), inRoi.begin(), inRoi.end(), rest.begin() );
         rest.resize( it - rest.begin() );
         result = rest;
       }
       break;
     }
     case 1: // OR
     {
       MITK_INFO << "OR";
       result = ExtractFiberIdSubset(children->ElementAt(0), storage);
       std::vector<long>::iterator it;
       for (unsigned int i=1; i<children->Size(); ++i)
       {
         it = result.end();
         std::vector<long> inRoi = ExtractFiberIdSubset(children->ElementAt(i), storage);
         result.insert(it, inRoi.begin(), inRoi.end());
       }
 
       // remove duplicates
       sort(result.begin(), result.end());
       it = unique(result.begin(), result.end());
       result.resize( it - result.begin() );
       break;
     }
     case 2: // NOT
     {
       MITK_INFO << "NOT";
       for(long i=0; i<this->GetNumFibers(); i++)
         result.push_back(i);
 
       std::vector<long>::iterator it;
       for (unsigned int i=0; i<children->Size(); ++i)
       {
         std::vector<long> inRoi = ExtractFiberIdSubset(children->ElementAt(i), storage);
 
         std::vector<long> rest(result.size()-inRoi.size());
         it = std::set_difference(result.begin(), result.end(), inRoi.begin(), inRoi.end(), rest.begin() );
         rest.resize( it - rest.begin() );
         result = rest;
       }
       break;
     }
     }
   }
   else if ( dynamic_cast<mitk::PlanarFigure*>(roi->GetData()) )  // actual extraction
   {
     if ( dynamic_cast<mitk::PlanarPolygon*>(roi->GetData()) )
     {
       mitk::PlanarFigure::Pointer planarPoly = dynamic_cast<mitk::PlanarFigure*>(roi->GetData());
 
       //create vtkPolygon using controlpoints from planarFigure polygon
       vtkSmartPointer<vtkPolygon> polygonVtk = vtkSmartPointer<vtkPolygon>::New();
       for (unsigned int i=0; i<planarPoly->GetNumberOfControlPoints(); ++i)
       {
         itk::Point<double,3> p = planarPoly->GetWorldControlPoint(i);
         vtkIdType id = polygonVtk->GetPoints()->InsertNextPoint(p[0], p[1], p[2] );
         polygonVtk->GetPointIds()->InsertNextId(id);
       }
 
       MITK_INFO << "Extracting with polygon";
       boost::progress_display disp(m_NumFibers);
       for (int i=0; i<m_NumFibers; i++)
       {
         ++disp ;
         vtkCell* cell = m_FiberPolyData->GetCell(i);
         int numPoints = cell->GetNumberOfPoints();
         vtkPoints* points = cell->GetPoints();
 
         for (int j=0; j<numPoints-1; j++)
         {
           // Inputs
           double p1[3] = {0,0,0};
           points->GetPoint(j, p1);
           double p2[3] = {0,0,0};
           points->GetPoint(j+1, p2);
           double tolerance = 0.001;
 
           // Outputs
           double t = 0; // Parametric coordinate of intersection (0 (corresponding to p1) to 1 (corresponding to p2))
           double x[3] = {0,0,0}; // The coordinate of the intersection
           double pcoords[3] = {0,0,0};
           int subId = 0;
 
           int iD = polygonVtk->IntersectWithLine(p1, p2, tolerance, t, x, pcoords, subId);
           if (iD!=0)
           {
             result.push_back(i);
             break;
           }
         }
       }
     }
     else if ( dynamic_cast<mitk::PlanarCircle*>(roi->GetData()) )
     {
       mitk::PlanarFigure::Pointer planarFigure = dynamic_cast<mitk::PlanarFigure*>(roi->GetData());
       Vector3D planeNormal = planarFigure->GetPlaneGeometry()->GetNormal();
       planeNormal.Normalize();
 
       //calculate circle radius
       mitk::Point3D V1w = planarFigure->GetWorldControlPoint(0); //centerPoint
       mitk::Point3D V2w  = planarFigure->GetWorldControlPoint(1); //radiusPoint
 
       double radius = V1w.EuclideanDistanceTo(V2w);
       radius *= radius;
 
       MITK_INFO << "Extracting with circle";
       boost::progress_display disp(m_NumFibers);
       for (int i=0; i<m_NumFibers; i++)
       {
         ++disp ;
         vtkCell* cell = m_FiberPolyData->GetCell(i);
         int numPoints = cell->GetNumberOfPoints();
         vtkPoints* points = cell->GetPoints();
 
         for (int j=0; j<numPoints-1; j++)
         {
           // Inputs
           double p1[3] = {0,0,0};
           points->GetPoint(j, p1);
           double p2[3] = {0,0,0};
           points->GetPoint(j+1, p2);
 
           // Outputs
           double t = 0; // Parametric coordinate of intersection (0 (corresponding to p1) to 1 (corresponding to p2))
           double x[3] = {0,0,0}; // The coordinate of the intersection
 
           int iD = vtkPlane::IntersectWithLine(p1,p2,planeNormal.GetDataPointer(),V1w.GetDataPointer(),t,x);
 
           if (iD!=0)
           {
             double dist = (x[0]-V1w[0])*(x[0]-V1w[0])+(x[1]-V1w[1])*(x[1]-V1w[1])+(x[2]-V1w[2])*(x[2]-V1w[2]);
             if( dist <= radius)
             {
               result.push_back(i);
               break;
             }
           }
         }
       }
     }
     return result;
   }
 
   return result;
 }
 
 void mitk::FiberBundle::UpdateFiberGeometry()
 {
   vtkSmartPointer<vtkCleanPolyData> cleaner = vtkSmartPointer<vtkCleanPolyData>::New();
   cleaner->SetInputData(m_FiberPolyData);
   cleaner->PointMergingOff();
   cleaner->Update();
   m_FiberPolyData = cleaner->GetOutput();
 
   m_FiberLengths.clear();
   m_MeanFiberLength = 0;
   m_MedianFiberLength = 0;
   m_LengthStDev = 0;
   m_NumFibers = m_FiberPolyData->GetNumberOfCells();
 
   if (m_FiberColors==nullptr || m_FiberColors->GetNumberOfTuples()!=m_FiberPolyData->GetNumberOfPoints())
     this->ColorFibersByOrientation();
 
   if (m_FiberWeights->GetNumberOfValues()!=m_NumFibers)
   {
     m_FiberWeights = vtkSmartPointer<vtkFloatArray>::New();
     m_FiberWeights->SetName("FIBER_WEIGHTS");
     m_FiberWeights->SetNumberOfValues(m_NumFibers);
     this->SetFiberWeights(1);
   }
 
   if (m_NumFibers<=0) // no fibers present; apply default geometry
   {
     m_MinFiberLength = 0;
     m_MaxFiberLength = 0;
     mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New();
     geometry->SetImageGeometry(false);
     float b[] = {0, 1, 0, 1, 0, 1};
     geometry->SetFloatBounds(b);
     SetGeometry(geometry);
     return;
   }
   double b[6];
   m_FiberPolyData->GetBounds(b);
 
   // calculate statistics
   for (int i=0; i<m_FiberPolyData->GetNumberOfCells(); i++)
   {
     vtkCell* cell = m_FiberPolyData->GetCell(i);
     int p = cell->GetNumberOfPoints();
     vtkPoints* points = cell->GetPoints();
     float length = 0;
     for (int j=0; j<p-1; j++)
     {
       double p1[3];
       points->GetPoint(j, p1);
       double p2[3];
       points->GetPoint(j+1, p2);
 
       float dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2]));
       length += dist;
     }
     m_FiberLengths.push_back(length);
     m_MeanFiberLength += length;
     if (i==0)
     {
       m_MinFiberLength = length;
       m_MaxFiberLength = length;
     }
     else
     {
       if (length<m_MinFiberLength)
         m_MinFiberLength = length;
       if (length>m_MaxFiberLength)
         m_MaxFiberLength = length;
     }
   }
   m_MeanFiberLength /= m_NumFibers;
 
   std::vector< float > sortedLengths = m_FiberLengths;
   std::sort(sortedLengths.begin(), sortedLengths.end());
   for (int i=0; i<m_NumFibers; i++)
     m_LengthStDev += (m_MeanFiberLength-sortedLengths.at(i))*(m_MeanFiberLength-sortedLengths.at(i));
   if (m_NumFibers>1)
     m_LengthStDev /= (m_NumFibers-1);
   else
     m_LengthStDev = 0;
   m_LengthStDev = std::sqrt(m_LengthStDev);
   m_MedianFiberLength = sortedLengths.at(m_NumFibers/2);
 
   mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New();
   geometry->SetFloatBounds(b);
   this->SetGeometry(geometry);
 
   m_UpdateTime3D.Modified();
   m_UpdateTime2D.Modified();
 }
 
 float mitk::FiberBundle::GetFiberWeight(unsigned int fiber) const
 {
   return m_FiberWeights->GetValue(fiber);
 }
 
 void mitk::FiberBundle::SetFiberWeights(float newWeight)
 {
   for (int i=0; i<m_FiberWeights->GetNumberOfValues(); i++)
     m_FiberWeights->SetValue(i, newWeight);
 }
 
 void mitk::FiberBundle::SetFiberWeights(vtkSmartPointer<vtkFloatArray> weights)
 {
   if (m_NumFibers!=weights->GetNumberOfValues())
   {
     MITK_INFO << "Weights array not equal to number of fibers! " << weights->GetNumberOfValues() << " vs " << m_NumFibers;
     return;
   }
 
   for (int i=0; i<weights->GetNumberOfValues(); i++)
     m_FiberWeights->SetValue(i, weights->GetValue(i));
 
   m_FiberWeights->SetName("FIBER_WEIGHTS");
 }
 
 void mitk::FiberBundle::SetFiberWeight(unsigned int fiber, float weight)
 {
   m_FiberWeights->SetValue(fiber, weight);
 }
 
 void mitk::FiberBundle::SetFiberColors(vtkSmartPointer<vtkUnsignedCharArray> fiberColors)
 {
   for(long i=0; i<m_FiberPolyData->GetNumberOfPoints(); ++i)
   {
     unsigned char source[4] = {0,0,0,0};
     fiberColors->GetTypedTuple(i, source);
 
     unsigned char target[4] = {0,0,0,0};
     target[0] = source[0];
     target[1] = source[1];
     target[2] = source[2];
     target[3] = source[3];
     m_FiberColors->InsertTypedTuple(i, target);
   }
   m_UpdateTime3D.Modified();
   m_UpdateTime2D.Modified();
 }
 
 itk::Matrix< double, 3, 3 > mitk::FiberBundle::TransformMatrix(itk::Matrix< double, 3, 3 > m, double rx, double ry, double rz)
 {
   rx = rx*M_PI/180;
   ry = ry*M_PI/180;
   rz = rz*M_PI/180;
 
   itk::Matrix< double, 3, 3 > rotX; rotX.SetIdentity();
   rotX[1][1] = cos(rx);
   rotX[2][2] = rotX[1][1];
   rotX[1][2] = -sin(rx);
   rotX[2][1] = -rotX[1][2];
 
   itk::Matrix< double, 3, 3 > rotY; rotY.SetIdentity();
   rotY[0][0] = cos(ry);
   rotY[2][2] = rotY[0][0];
   rotY[0][2] = sin(ry);
   rotY[2][0] = -rotY[0][2];
 
   itk::Matrix< double, 3, 3 > rotZ; rotZ.SetIdentity();
   rotZ[0][0] = cos(rz);
   rotZ[1][1] = rotZ[0][0];
   rotZ[0][1] = -sin(rz);
   rotZ[1][0] = -rotZ[0][1];
 
   itk::Matrix< double, 3, 3 > rot = rotZ*rotY*rotX;
 
   m = rot*m;
 
   return m;
 }
 
 itk::Point<float, 3> mitk::FiberBundle::TransformPoint(vnl_vector_fixed< double, 3 > point, double rx, double ry, double rz, double tx, double ty, double tz)
 {
   rx = rx*M_PI/180;
   ry = ry*M_PI/180;
   rz = rz*M_PI/180;
 
   vnl_matrix_fixed< double, 3, 3 > rotX; rotX.set_identity();
   rotX[1][1] = cos(rx);
   rotX[2][2] = rotX[1][1];
   rotX[1][2] = -sin(rx);
   rotX[2][1] = -rotX[1][2];
 
   vnl_matrix_fixed< double, 3, 3 > rotY; rotY.set_identity();
   rotY[0][0] = cos(ry);
   rotY[2][2] = rotY[0][0];
   rotY[0][2] = sin(ry);
   rotY[2][0] = -rotY[0][2];
 
   vnl_matrix_fixed< double, 3, 3 > rotZ; rotZ.set_identity();
   rotZ[0][0] = cos(rz);
   rotZ[1][1] = rotZ[0][0];
   rotZ[0][1] = -sin(rz);
   rotZ[1][0] = -rotZ[0][1];
 
   vnl_matrix_fixed< double, 3, 3 > rot = rotZ*rotY*rotX;
 
   mitk::BaseGeometry::Pointer geom = this->GetGeometry();
   mitk::Point3D center = geom->GetCenter();
 
   point[0] -= center[0];
   point[1] -= center[1];
   point[2] -= center[2];
   point = rot*point;
   point[0] += center[0]+tx;
   point[1] += center[1]+ty;
   point[2] += center[2]+tz;
   itk::Point<float, 3> out; out[0] = point[0]; out[1] = point[1]; out[2] = point[2];
   return out;
 }
 
 void mitk::FiberBundle::TransformFibers(double rx, double ry, double rz, double tx, double ty, double tz)
 {
   rx = rx*M_PI/180;
   ry = ry*M_PI/180;
   rz = rz*M_PI/180;
 
   vnl_matrix_fixed< double, 3, 3 > rotX; rotX.set_identity();
   rotX[1][1] = cos(rx);
   rotX[2][2] = rotX[1][1];
   rotX[1][2] = -sin(rx);
   rotX[2][1] = -rotX[1][2];
 
   vnl_matrix_fixed< double, 3, 3 > rotY; rotY.set_identity();
   rotY[0][0] = cos(ry);
   rotY[2][2] = rotY[0][0];
   rotY[0][2] = sin(ry);
   rotY[2][0] = -rotY[0][2];
 
   vnl_matrix_fixed< double, 3, 3 > rotZ; rotZ.set_identity();
   rotZ[0][0] = cos(rz);
   rotZ[1][1] = rotZ[0][0];
   rotZ[0][1] = -sin(rz);
   rotZ[1][0] = -rotZ[0][1];
 
   vnl_matrix_fixed< double, 3, 3 > rot = rotZ*rotY*rotX;
 
   mitk::BaseGeometry::Pointer geom = this->GetGeometry();
   mitk::Point3D center = geom->GetCenter();
 
   vtkSmartPointer<vtkPoints> vtkNewPoints = vtkSmartPointer<vtkPoints>::New();
   vtkSmartPointer<vtkCellArray> vtkNewCells = vtkSmartPointer<vtkCellArray>::New();
 
   for (int i=0; i<m_NumFibers; i++)
   {
     vtkCell* cell = m_FiberPolyData->GetCell(i);
     int numPoints = cell->GetNumberOfPoints();
     vtkPoints* points = cell->GetPoints();
 
     vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New();
     for (int j=0; j<numPoints; j++)
     {
       double* p = points->GetPoint(j);
       vnl_vector_fixed< double, 3 > dir;
       dir[0] = p[0]-center[0];
       dir[1] = p[1]-center[1];
       dir[2] = p[2]-center[2];
       dir = rot*dir;
       dir[0] += center[0]+tx;
       dir[1] += center[1]+ty;
       dir[2] += center[2]+tz;
       vtkIdType id = vtkNewPoints->InsertNextPoint(dir.data_block());
       container->GetPointIds()->InsertNextId(id);
     }
     vtkNewCells->InsertNextCell(container);
   }
 
   m_FiberPolyData = vtkSmartPointer<vtkPolyData>::New();
   m_FiberPolyData->SetPoints(vtkNewPoints);
   m_FiberPolyData->SetLines(vtkNewCells);
   this->SetFiberPolyData(m_FiberPolyData, true);
 }
 
 void mitk::FiberBundle::RotateAroundAxis(double x, double y, double z)
 {
   x = x*M_PI/180;
   y = y*M_PI/180;
   z = z*M_PI/180;
 
   vnl_matrix_fixed< double, 3, 3 > rotX; rotX.set_identity();
   rotX[1][1] = cos(x);
   rotX[2][2] = rotX[1][1];
   rotX[1][2] = -sin(x);
   rotX[2][1] = -rotX[1][2];
 
   vnl_matrix_fixed< double, 3, 3 > rotY; rotY.set_identity();
   rotY[0][0] = cos(y);
   rotY[2][2] = rotY[0][0];
   rotY[0][2] = sin(y);
   rotY[2][0] = -rotY[0][2];
 
   vnl_matrix_fixed< double, 3, 3 > rotZ; rotZ.set_identity();
   rotZ[0][0] = cos(z);
   rotZ[1][1] = rotZ[0][0];
   rotZ[0][1] = -sin(z);
   rotZ[1][0] = -rotZ[0][1];
 
   mitk::BaseGeometry::Pointer geom = this->GetGeometry();
   mitk::Point3D center = geom->GetCenter();
 
   vtkSmartPointer<vtkPoints> vtkNewPoints = vtkSmartPointer<vtkPoints>::New();
   vtkSmartPointer<vtkCellArray> vtkNewCells = vtkSmartPointer<vtkCellArray>::New();
 
   for (int i=0; i<m_NumFibers; i++)
   {
     vtkCell* cell = m_FiberPolyData->GetCell(i);
     int numPoints = cell->GetNumberOfPoints();
     vtkPoints* points = cell->GetPoints();
 
     vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New();
     for (int j=0; j<numPoints; j++)
     {
       double* p = points->GetPoint(j);
       vnl_vector_fixed< double, 3 > dir;
       dir[0] = p[0]-center[0];
       dir[1] = p[1]-center[1];
       dir[2] = p[2]-center[2];
       dir = rotZ*rotY*rotX*dir;
       dir[0] += center[0];
       dir[1] += center[1];
       dir[2] += center[2];
       vtkIdType id = vtkNewPoints->InsertNextPoint(dir.data_block());
       container->GetPointIds()->InsertNextId(id);
     }
     vtkNewCells->InsertNextCell(container);
   }
 
   m_FiberPolyData = vtkSmartPointer<vtkPolyData>::New();
   m_FiberPolyData->SetPoints(vtkNewPoints);
   m_FiberPolyData->SetLines(vtkNewCells);
   this->SetFiberPolyData(m_FiberPolyData, true);
 }
 
 void mitk::FiberBundle::ScaleFibers(double x, double y, double z, bool subtractCenter)
 {
   MITK_INFO << "Scaling fibers";
   boost::progress_display disp(m_NumFibers);
 
   mitk::BaseGeometry* geom = this->GetGeometry();
   mitk::Point3D c = geom->GetCenter();
 
   vtkSmartPointer<vtkPoints> vtkNewPoints = vtkSmartPointer<vtkPoints>::New();
   vtkSmartPointer<vtkCellArray> vtkNewCells = vtkSmartPointer<vtkCellArray>::New();
 
   for (int i=0; i<m_NumFibers; i++)
   {
     ++disp ;
     vtkCell* cell = m_FiberPolyData->GetCell(i);
     int numPoints = cell->GetNumberOfPoints();
     vtkPoints* points = cell->GetPoints();
 
     vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New();
     for (int j=0; j<numPoints; j++)
     {
       double* p = points->GetPoint(j);
       if (subtractCenter)
       {
         p[0] -= c[0]; p[1] -= c[1]; p[2] -= c[2];
       }
       p[0] *= x;
       p[1] *= y;
       p[2] *= z;
       if (subtractCenter)
       {
         p[0] += c[0]; p[1] += c[1]; p[2] += c[2];
       }
       vtkIdType id = vtkNewPoints->InsertNextPoint(p);
       container->GetPointIds()->InsertNextId(id);
     }
     vtkNewCells->InsertNextCell(container);
   }
 
   m_FiberPolyData = vtkSmartPointer<vtkPolyData>::New();
   m_FiberPolyData->SetPoints(vtkNewPoints);
   m_FiberPolyData->SetLines(vtkNewCells);
   this->SetFiberPolyData(m_FiberPolyData, true);
 }
 
 void mitk::FiberBundle::TranslateFibers(double x, double y, double z)
 {
   vtkSmartPointer<vtkPoints> vtkNewPoints = vtkSmartPointer<vtkPoints>::New();
   vtkSmartPointer<vtkCellArray> vtkNewCells = vtkSmartPointer<vtkCellArray>::New();
 
   for (int i=0; i<m_NumFibers; i++)
   {
     vtkCell* cell = m_FiberPolyData->GetCell(i);
     int numPoints = cell->GetNumberOfPoints();
     vtkPoints* points = cell->GetPoints();
 
     vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New();
     for (int j=0; j<numPoints; j++)
     {
       double* p = points->GetPoint(j);
       p[0] += x;
       p[1] += y;
       p[2] += z;
       vtkIdType id = vtkNewPoints->InsertNextPoint(p);
       container->GetPointIds()->InsertNextId(id);
     }
     vtkNewCells->InsertNextCell(container);
   }
 
   m_FiberPolyData = vtkSmartPointer<vtkPolyData>::New();
   m_FiberPolyData->SetPoints(vtkNewPoints);
   m_FiberPolyData->SetLines(vtkNewCells);
   this->SetFiberPolyData(m_FiberPolyData, true);
 }
 
 void mitk::FiberBundle::MirrorFibers(unsigned int axis)
 {
   if (axis>2)
     return;
 
   MITK_INFO << "Mirroring fibers";
   boost::progress_display disp(m_NumFibers);
 
   vtkSmartPointer<vtkPoints> vtkNewPoints = vtkSmartPointer<vtkPoints>::New();
   vtkSmartPointer<vtkCellArray> vtkNewCells = vtkSmartPointer<vtkCellArray>::New();
 
   for (int i=0; i<m_NumFibers; i++)
   {
     ++disp;
     vtkCell* cell = m_FiberPolyData->GetCell(i);
     int numPoints = cell->GetNumberOfPoints();
     vtkPoints* points = cell->GetPoints();
 
     vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New();
     for (int j=0; j<numPoints; j++)
     {
       double* p = points->GetPoint(j);
       p[axis] = -p[axis];
       vtkIdType id = vtkNewPoints->InsertNextPoint(p);
       container->GetPointIds()->InsertNextId(id);
     }
     vtkNewCells->InsertNextCell(container);
   }
 
   m_FiberPolyData = vtkSmartPointer<vtkPolyData>::New();
   m_FiberPolyData->SetPoints(vtkNewPoints);
   m_FiberPolyData->SetLines(vtkNewCells);
   this->SetFiberPolyData(m_FiberPolyData, true);
 }
 
 void mitk::FiberBundle::RemoveDir(vnl_vector_fixed<double,3> dir, double threshold)
 {
   dir.normalize();
   vtkSmartPointer<vtkPoints> vtkNewPoints = vtkSmartPointer<vtkPoints>::New();
   vtkSmartPointer<vtkCellArray> vtkNewCells = vtkSmartPointer<vtkCellArray>::New();
 
   boost::progress_display disp(m_FiberPolyData->GetNumberOfCells());
   for (int i=0; i<m_FiberPolyData->GetNumberOfCells(); i++)
   {
     ++disp ;
     vtkCell* cell = m_FiberPolyData->GetCell(i);
     int numPoints = cell->GetNumberOfPoints();
     vtkPoints* points = cell->GetPoints();
 
     // calculate curvatures
     vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New();
     bool discard = false;
     for (int j=0; j<numPoints-1; j++)
     {
       double p1[3];
       points->GetPoint(j, p1);
       double p2[3];
       points->GetPoint(j+1, p2);
 
       vnl_vector_fixed< double, 3 > v1;
       v1[0] = p2[0]-p1[0];
       v1[1] = p2[1]-p1[1];
       v1[2] = p2[2]-p1[2];
       if (v1.magnitude()>0.001)
       {
         v1.normalize();
 
         if (fabs(dot_product(v1,dir))>threshold)
         {
           discard = true;
           break;
         }
       }
     }
     if (!discard)
     {
       for (int j=0; j<numPoints; j++)
       {
         double p1[3];
         points->GetPoint(j, p1);
 
         vtkIdType id = vtkNewPoints->InsertNextPoint(p1);
         container->GetPointIds()->InsertNextId(id);
       }
       vtkNewCells->InsertNextCell(container);
     }
   }
 
   m_FiberPolyData = vtkSmartPointer<vtkPolyData>::New();
   m_FiberPolyData->SetPoints(vtkNewPoints);
   m_FiberPolyData->SetLines(vtkNewCells);
 
   this->SetFiberPolyData(m_FiberPolyData, true);
 
   //    UpdateColorCoding();
   //    UpdateFiberGeometry();
 }
 
 bool mitk::FiberBundle::ApplyCurvatureThreshold(float minRadius, bool deleteFibers)
 {
   if (minRadius<0)
     return true;
 
   vtkSmartPointer<vtkPoints> vtkNewPoints = vtkSmartPointer<vtkPoints>::New();
   vtkSmartPointer<vtkCellArray> vtkNewCells = vtkSmartPointer<vtkCellArray>::New();
 
   MITK_INFO << "Applying curvature threshold";
   boost::progress_display disp(m_FiberPolyData->GetNumberOfCells());
   for (int i=0; i<m_FiberPolyData->GetNumberOfCells(); i++)
   {
     ++disp ;
     vtkCell* cell = m_FiberPolyData->GetCell(i);
     int numPoints = cell->GetNumberOfPoints();
     vtkPoints* points = cell->GetPoints();
 
     // calculate curvatures
     vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New();
     for (int j=0; j<numPoints-2; j++)
     {
       double p1[3];
       points->GetPoint(j, p1);
       double p2[3];
       points->GetPoint(j+1, p2);
       double p3[3];
       points->GetPoint(j+2, p3);
 
       vnl_vector_fixed< float, 3 > v1, v2, v3;
 
       v1[0] = p2[0]-p1[0];
       v1[1] = p2[1]-p1[1];
       v1[2] = p2[2]-p1[2];
 
       v2[0] = p3[0]-p2[0];
       v2[1] = p3[1]-p2[1];
       v2[2] = p3[2]-p2[2];
 
       v3[0] = p1[0]-p3[0];
       v3[1] = p1[1]-p3[1];
       v3[2] = p1[2]-p3[2];
 
       float a = v1.magnitude();
       float b = v2.magnitude();
       float c = v3.magnitude();
       float r = a*b*c/std::sqrt((a+b+c)*(a+b-c)*(b+c-a)*(a-b+c)); // radius of triangle via Heron's formula (area of triangle)
 
       vtkIdType id = vtkNewPoints->InsertNextPoint(p1);
       container->GetPointIds()->InsertNextId(id);
 
       if (deleteFibers && r<minRadius)
         break;
 
       if (r<minRadius)
       {
         j += 2;
         vtkNewCells->InsertNextCell(container);
         container = vtkSmartPointer<vtkPolyLine>::New();
       }
       else if (j==numPoints-3)
       {
         id = vtkNewPoints->InsertNextPoint(p2);
         container->GetPointIds()->InsertNextId(id);
         id = vtkNewPoints->InsertNextPoint(p3);
         container->GetPointIds()->InsertNextId(id);
         vtkNewCells->InsertNextCell(container);
       }
     }
   }
 
   if (vtkNewCells->GetNumberOfCells()<=0)
     return false;
 
   m_FiberPolyData = vtkSmartPointer<vtkPolyData>::New();
   m_FiberPolyData->SetPoints(vtkNewPoints);
   m_FiberPolyData->SetLines(vtkNewCells);
   this->SetFiberPolyData(m_FiberPolyData, true);
   return true;
 }
 
 bool mitk::FiberBundle::RemoveShortFibers(float lengthInMM)
 {
   MITK_INFO << "Removing short fibers";
   if (lengthInMM<=0 || lengthInMM<m_MinFiberLength)
   {
     MITK_INFO << "No fibers shorter than " << lengthInMM << " mm found!";
     return true;
   }
 
   if (lengthInMM>m_MaxFiberLength)    // can't remove all fibers
   {
     MITK_WARN << "Process aborted. No fibers would be left!";
     return false;
   }
 
   vtkSmartPointer<vtkPoints> vtkNewPoints = vtkSmartPointer<vtkPoints>::New();
   vtkSmartPointer<vtkCellArray> vtkNewCells = vtkSmartPointer<vtkCellArray>::New();
   float min = m_MaxFiberLength;
 
   boost::progress_display disp(m_NumFibers);
   for (int i=0; i<m_NumFibers; i++)
   {
     ++disp;
     vtkCell* cell = m_FiberPolyData->GetCell(i);
     int numPoints = cell->GetNumberOfPoints();
     vtkPoints* points = cell->GetPoints();
 
     if (m_FiberLengths.at(i)>=lengthInMM)
     {
       vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New();
       for (int j=0; j<numPoints; j++)
       {
         double* p = points->GetPoint(j);
         vtkIdType id = vtkNewPoints->InsertNextPoint(p);
         container->GetPointIds()->InsertNextId(id);
       }
       vtkNewCells->InsertNextCell(container);
       if (m_FiberLengths.at(i)<min)
         min = m_FiberLengths.at(i);
     }
   }
 
   if (vtkNewCells->GetNumberOfCells()<=0)
     return false;
 
   m_FiberPolyData = vtkSmartPointer<vtkPolyData>::New();
   m_FiberPolyData->SetPoints(vtkNewPoints);
   m_FiberPolyData->SetLines(vtkNewCells);
   this->SetFiberPolyData(m_FiberPolyData, true);
   return true;
 }
 
 bool mitk::FiberBundle::RemoveLongFibers(float lengthInMM)
 {
   if (lengthInMM<=0 || lengthInMM>m_MaxFiberLength)
     return true;
 
   if (lengthInMM<m_MinFiberLength)    // can't remove all fibers
     return false;
 
   vtkSmartPointer<vtkPoints> vtkNewPoints = vtkSmartPointer<vtkPoints>::New();
   vtkSmartPointer<vtkCellArray> vtkNewCells = vtkSmartPointer<vtkCellArray>::New();
 
   MITK_INFO << "Removing long fibers";
   boost::progress_display disp(m_NumFibers);
   for (int i=0; i<m_NumFibers; i++)
   {
     ++disp;
     vtkCell* cell = m_FiberPolyData->GetCell(i);
     int numPoints = cell->GetNumberOfPoints();
     vtkPoints* points = cell->GetPoints();
 
     if (m_FiberLengths.at(i)<=lengthInMM)
     {
       vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New();
       for (int j=0; j<numPoints; j++)
       {
         double* p = points->GetPoint(j);
         vtkIdType id = vtkNewPoints->InsertNextPoint(p);
         container->GetPointIds()->InsertNextId(id);
       }
       vtkNewCells->InsertNextCell(container);
     }
   }
 
   if (vtkNewCells->GetNumberOfCells()<=0)
     return false;
 
   m_FiberPolyData = vtkSmartPointer<vtkPolyData>::New();
   m_FiberPolyData->SetPoints(vtkNewPoints);
   m_FiberPolyData->SetLines(vtkNewCells);
   this->SetFiberPolyData(m_FiberPolyData, true);
   return true;
 }
 
 void mitk::FiberBundle::ResampleSpline(float pointDistance, double tension, double continuity, double bias )
 {
   if (pointDistance<=0)
     return;
 
   vtkSmartPointer<vtkPoints> vtkSmoothPoints = vtkSmartPointer<vtkPoints>::New(); //in smoothpoints the interpolated points representing a fiber are stored.
 
   //in vtkcells all polylines are stored, actually all id's of them are stored
   vtkSmartPointer<vtkCellArray> vtkSmoothCells = vtkSmartPointer<vtkCellArray>::New(); //cellcontainer for smoothed lines
   vtkIdType pointHelperCnt = 0;
 
   MITK_INFO << "Smoothing fibers";
   vtkSmartPointer<vtkFloatArray> newFiberWeights = vtkSmartPointer<vtkFloatArray>::New();
   newFiberWeights->SetName("FIBER_WEIGHTS");
   newFiberWeights->SetNumberOfValues(m_NumFibers);
 
   boost::progress_display disp(m_NumFibers);
 #pragma omp parallel for
   for (int i=0; i<m_NumFibers; i++)
   {
     vtkSmartPointer<vtkPoints> newPoints = vtkSmartPointer<vtkPoints>::New();
     float length = 0;
     float weight = 1;
 #pragma omp critical
     {
       length = m_FiberLengths.at(i);
       weight = m_FiberWeights->GetValue(i);
       ++disp;
       vtkCell* cell = m_FiberPolyData->GetCell(i);
       int numPoints = cell->GetNumberOfPoints();
       vtkPoints* points = cell->GetPoints();
       for (int j=0; j<numPoints; j++)
         newPoints->InsertNextPoint(points->GetPoint(j));
     }
 
     int sampling = std::ceil(length/pointDistance);
 
     vtkSmartPointer<vtkKochanekSpline> xSpline = vtkSmartPointer<vtkKochanekSpline>::New();
     vtkSmartPointer<vtkKochanekSpline> ySpline = vtkSmartPointer<vtkKochanekSpline>::New();
     vtkSmartPointer<vtkKochanekSpline> zSpline = vtkSmartPointer<vtkKochanekSpline>::New();
     xSpline->SetDefaultBias(bias); xSpline->SetDefaultTension(tension); xSpline->SetDefaultContinuity(continuity);
     ySpline->SetDefaultBias(bias); ySpline->SetDefaultTension(tension); ySpline->SetDefaultContinuity(continuity);
     zSpline->SetDefaultBias(bias); zSpline->SetDefaultTension(tension); zSpline->SetDefaultContinuity(continuity);
 
     vtkSmartPointer<vtkParametricSpline> spline = vtkSmartPointer<vtkParametricSpline>::New();
     spline->SetXSpline(xSpline);
     spline->SetYSpline(ySpline);
     spline->SetZSpline(zSpline);
     spline->SetPoints(newPoints);
 
     vtkSmartPointer<vtkParametricFunctionSource> functionSource = vtkSmartPointer<vtkParametricFunctionSource>::New();
     functionSource->SetParametricFunction(spline);
     functionSource->SetUResolution(sampling);
     functionSource->SetVResolution(sampling);
     functionSource->SetWResolution(sampling);
     functionSource->Update();
 
     vtkPolyData* outputFunction = functionSource->GetOutput();
     vtkPoints* tmpSmoothPnts = outputFunction->GetPoints(); //smoothPoints of current fiber
 
     vtkSmartPointer<vtkPolyLine> smoothLine = vtkSmartPointer<vtkPolyLine>::New();
     smoothLine->GetPointIds()->SetNumberOfIds(tmpSmoothPnts->GetNumberOfPoints());
 
 #pragma omp critical
     {
       for (int j=0; j<smoothLine->GetNumberOfPoints(); j++)
       {
         smoothLine->GetPointIds()->SetId(j, j+pointHelperCnt);
         vtkSmoothPoints->InsertNextPoint(tmpSmoothPnts->GetPoint(j));
       }
 
       newFiberWeights->SetValue(vtkSmoothCells->GetNumberOfCells(), weight);
       vtkSmoothCells->InsertNextCell(smoothLine);
       pointHelperCnt += tmpSmoothPnts->GetNumberOfPoints();
     }
   }
 
   SetFiberWeights(newFiberWeights);
   m_FiberPolyData = vtkSmartPointer<vtkPolyData>::New();
   m_FiberPolyData->SetPoints(vtkSmoothPoints);
   m_FiberPolyData->SetLines(vtkSmoothCells);
   this->SetFiberPolyData(m_FiberPolyData, true);
 }
 
 void mitk::FiberBundle::ResampleSpline(float pointDistance)
 {
   ResampleSpline(pointDistance, 0, 0, 0 );
 }
 
 unsigned long mitk::FiberBundle::GetNumberOfPoints() const
 {
   unsigned long points = 0;
   for (int i=0; i<m_FiberPolyData->GetNumberOfCells(); i++)
   {
     vtkCell* cell = m_FiberPolyData->GetCell(i);
     points += cell->GetNumberOfPoints();
   }
   return points;
 }
 
 void mitk::FiberBundle::Compress(float error)
 {
   vtkSmartPointer<vtkPoints> vtkNewPoints = vtkSmartPointer<vtkPoints>::New();
   vtkSmartPointer<vtkCellArray> vtkNewCells = vtkSmartPointer<vtkCellArray>::New();
 
   MITK_INFO << "Compressing fibers";
   unsigned long numRemovedPoints = 0;
   boost::progress_display disp(m_FiberPolyData->GetNumberOfCells());
   vtkSmartPointer<vtkFloatArray> newFiberWeights = vtkSmartPointer<vtkFloatArray>::New();
   newFiberWeights->SetName("FIBER_WEIGHTS");
   newFiberWeights->SetNumberOfValues(m_NumFibers);
 
 #pragma omp parallel for
   for (int i=0; i<m_FiberPolyData->GetNumberOfCells(); i++)
   {
 
     std::vector< vnl_vector_fixed< double, 3 > > vertices;
     float weight = 1;
 
 #pragma omp critical
     {
       ++disp;
       weight = m_FiberWeights->GetValue(i);
       vtkCell* cell = m_FiberPolyData->GetCell(i);
       int numPoints = cell->GetNumberOfPoints();
       vtkPoints* points = cell->GetPoints();
 
       for (int j=0; j<numPoints; j++)
       {
         double cand[3];
         points->GetPoint(j, cand);
         vnl_vector_fixed< double, 3 > candV;
         candV[0]=cand[0]; candV[1]=cand[1]; candV[2]=cand[2];
         vertices.push_back(candV);
       }
     }
 
     // calculate curvatures
     int numPoints = vertices.size();
     std::vector< int > removedPoints; removedPoints.resize(numPoints, 0);
     removedPoints[0]=-1; removedPoints[numPoints-1]=-1;
 
     vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New();
     int remCounter = 0;
 
     bool pointFound = true;
     while (pointFound)
     {
       pointFound = false;
       double minError = error;
       int removeIndex = -1;
 
       for (unsigned int j=0; j<vertices.size(); j++)
       {
         if (removedPoints[j]==0)
         {
           vnl_vector_fixed< double, 3 > candV = vertices.at(j);
 
           int validP = -1;
           vnl_vector_fixed< double, 3 > pred;
           for (int k=j-1; k>=0; k--)
             if (removedPoints[k]<=0)
             {
               pred = vertices.at(k);
               validP = k;
               break;
             }
           int validS = -1;
           vnl_vector_fixed< double, 3 > succ;
           for (int k=j+1; k<numPoints; k++)
             if (removedPoints[k]<=0)
             {
               succ = vertices.at(k);
               validS = k;
               break;
             }
 
           if (validP>=0 && validS>=0)
           {
             double a = (candV-pred).magnitude();
             double b = (candV-succ).magnitude();
             double c = (pred-succ).magnitude();
             double s=0.5*(a+b+c);
             double hc=(2.0/c)*sqrt(fabs(s*(s-a)*(s-b)*(s-c)));
 
             if (hc<minError)
             {
               removeIndex = j;
               minError = hc;
               pointFound = true;
             }
           }
         }
       }
 
       if (pointFound)
       {
         removedPoints[removeIndex] = 1;
         remCounter++;
       }
     }
 
     for (int j=0; j<numPoints; j++)
     {
       if (removedPoints[j]<=0)
       {
 #pragma omp critical
         {
           vtkIdType id = vtkNewPoints->InsertNextPoint(vertices.at(j).data_block());
           container->GetPointIds()->InsertNextId(id);
         }
       }
     }
 
 #pragma omp critical
     {
       newFiberWeights->SetValue(vtkNewCells->GetNumberOfCells(), weight);
       numRemovedPoints += remCounter;
       vtkNewCells->InsertNextCell(container);
     }
   }
 
   if (vtkNewCells->GetNumberOfCells()>0)
   {
     MITK_INFO << "Removed points: " << numRemovedPoints;
     SetFiberWeights(newFiberWeights);
     m_FiberPolyData = vtkSmartPointer<vtkPolyData>::New();
     m_FiberPolyData->SetPoints(vtkNewPoints);
     m_FiberPolyData->SetLines(vtkNewCells);
     this->SetFiberPolyData(m_FiberPolyData, true);
   }
 }
 
 void mitk::FiberBundle::ResampleLinear(double pointDistance)
 {
   vtkSmartPointer<vtkPoints> vtkNewPoints = vtkSmartPointer<vtkPoints>::New();
   vtkSmartPointer<vtkCellArray> vtkNewCells = vtkSmartPointer<vtkCellArray>::New();
 
   MITK_INFO << "Resampling fibers (linear)";
   boost::progress_display disp(m_FiberPolyData->GetNumberOfCells());
   vtkSmartPointer<vtkFloatArray> newFiberWeights = vtkSmartPointer<vtkFloatArray>::New();
   newFiberWeights->SetName("FIBER_WEIGHTS");
   newFiberWeights->SetNumberOfValues(m_NumFibers);
 
 #pragma omp parallel for
   for (int i=0; i<m_FiberPolyData->GetNumberOfCells(); i++)
   {
 
     std::vector< vnl_vector_fixed< double, 3 > > vertices;
     float weight = 1;
 
 #pragma omp critical
     {
       ++disp;
       weight = m_FiberWeights->GetValue(i);
       vtkCell* cell = m_FiberPolyData->GetCell(i);
       int numPoints = cell->GetNumberOfPoints();
       vtkPoints* points = cell->GetPoints();
 
       for (int j=0; j<numPoints; j++)
       {
         double cand[3];
         points->GetPoint(j, cand);
         vnl_vector_fixed< double, 3 > candV;
         candV[0]=cand[0]; candV[1]=cand[1]; candV[2]=cand[2];
         vertices.push_back(candV);
       }
     }
 
     vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New();
     vnl_vector_fixed< double, 3 > lastV = vertices.at(0);
 
 #pragma omp critical
     {
       vtkIdType id = vtkNewPoints->InsertNextPoint(lastV.data_block());
       container->GetPointIds()->InsertNextId(id);
     }
     for (unsigned int j=1; j<vertices.size(); j++)
     {
       vnl_vector_fixed< double, 3 > vec = vertices.at(j) - lastV;
       double new_dist = vec.magnitude();
 
       if (new_dist >= pointDistance)
       {
         vnl_vector_fixed< double, 3 > newV = lastV;
         if ( new_dist-pointDistance <= mitk::eps )
         {
           vec.normalize();
           newV += vec * pointDistance;
         }
         else
         {
           // intersection between sphere (radius 'pointDistance', center 'lastV') and line (direction 'd' and point 'p')
           vnl_vector_fixed< double, 3 > p = vertices.at(j-1);
           vnl_vector_fixed< double, 3 > d = vertices.at(j) - p;
 
           double a = d[0]*d[0] + d[1]*d[1] + d[2]*d[2];
           double b = 2 * (d[0] * (p[0] - lastV[0]) + d[1] * (p[1] - lastV[1]) + d[2] * (p[2] - lastV[2]));
           double c = (p[0] - lastV[0])*(p[0] - lastV[0]) + (p[1] - lastV[1])*(p[1] - lastV[1]) + (p[2] - lastV[2])*(p[2] - lastV[2]) - pointDistance*pointDistance;
 
           double v1 =(-b + std::sqrt(b*b-4*a*c))/(2*a);
           double v2 =(-b - std::sqrt(b*b-4*a*c))/(2*a);
 
           if (v1>0)
             newV = p + d * v1;
           else if (v2>0)
             newV = p + d * v2;
           else
             MITK_INFO << "ERROR1 - linear resampling";
 
           j--;
         }
 
 #pragma omp critical
         {
           vtkIdType id = vtkNewPoints->InsertNextPoint(newV.data_block());
           container->GetPointIds()->InsertNextId(id);
         }
         lastV = newV;
       }
       else if (j==vertices.size()-1 && new_dist>0.0001)
       {
 #pragma omp critical
         {
           vtkIdType id = vtkNewPoints->InsertNextPoint(vertices.at(j).data_block());
           container->GetPointIds()->InsertNextId(id);
         }
       }
     }
 
 #pragma omp critical
     {
       newFiberWeights->SetValue(vtkNewCells->GetNumberOfCells(), weight);
       vtkNewCells->InsertNextCell(container);
     }
   }
 
   if (vtkNewCells->GetNumberOfCells()>0)
   {
     SetFiberWeights(newFiberWeights);
     m_FiberPolyData = vtkSmartPointer<vtkPolyData>::New();
     m_FiberPolyData->SetPoints(vtkNewPoints);
     m_FiberPolyData->SetLines(vtkNewCells);
     this->SetFiberPolyData(m_FiberPolyData, true);
   }
 }
 
 // reapply selected colorcoding in case PolyData structure has changed
 bool mitk::FiberBundle::Equals(mitk::FiberBundle* fib, double eps)
 {
   if (fib==nullptr)
   {
     MITK_INFO << "Reference bundle is nullptr!";
     return false;
   }
 
   if (m_NumFibers!=fib->GetNumFibers())
   {
     MITK_INFO << "Unequal number of fibers!";
     MITK_INFO << m_NumFibers << " vs. " << fib->GetNumFibers();
     return false;
   }
 
   for (int i=0; i<m_NumFibers; i++)
   {
     vtkCell* cell = m_FiberPolyData->GetCell(i);
     int numPoints = cell->GetNumberOfPoints();
     vtkPoints* points = cell->GetPoints();
 
     vtkCell* cell2 = fib->GetFiberPolyData()->GetCell(i);
     int numPoints2 = cell2->GetNumberOfPoints();
     vtkPoints* points2 = cell2->GetPoints();
 
     if (numPoints2!=numPoints)
     {
       MITK_INFO << "Unequal number of points in fiber " << i << "!";
       MITK_INFO << numPoints2 << " vs. " << numPoints;
       return false;
     }
 
     for (int j=0; j<numPoints; j++)
     {
       double* p1 = points->GetPoint(j);
       double* p2 = points2->GetPoint(j);
       if (fabs(p1[0]-p2[0])>eps || fabs(p1[1]-p2[1])>eps || fabs(p1[2]-p2[2])>eps)
       {
         MITK_INFO << "Unequal points in fiber " << i << " at position " << j << "!";
         MITK_INFO << "p1: " << p1[0] << ", " << p1[1] << ", " << p1[2];
         MITK_INFO << "p2: " << p2[0] << ", " << p2[1] << ", " << p2[2];
         return false;
       }
     }
   }
 
   return true;
 }
 
 void mitk::FiberBundle::PrintSelf(std::ostream &os, itk::Indent indent) const
 {
   os << indent << this->GetNameOfClass() << ":\n";
   os << indent << "Number of fibers: " << this->GetNumFibers() << std::endl;
   os << indent << "Min. fiber length: " << this->GetMinFiberLength() << std::endl;
   os << indent << "Max. fiber length: " << this->GetMaxFiberLength() << std::endl;
   os << indent << "Mean fiber length: " << this->GetMeanFiberLength() << std::endl;
   os << indent << "Median fiber length: " << this->GetMedianFiberLength() << std::endl;
   os << indent << "STDEV fiber length: " << this->GetLengthStDev() << std::endl;
   os << indent << "Number of points: " << this->GetNumberOfPoints() << std::endl;
   Superclass::PrintSelf(os, indent);
 }
 
 /* ESSENTIAL IMPLEMENTATION OF SUPERCLASS METHODS */
 void mitk::FiberBundle::UpdateOutputInformation()
 {
 
 }
 void mitk::FiberBundle::SetRequestedRegionToLargestPossibleRegion()
 {
 
 }
 bool mitk::FiberBundle::RequestedRegionIsOutsideOfTheBufferedRegion()
 {
   return false;
 }
 bool mitk::FiberBundle::VerifyRequestedRegion()
 {
   return true;
 }
 void mitk::FiberBundle::SetRequestedRegion(const itk::DataObject* )
 {
 
 }
diff --git a/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.h b/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.h
index a49a44e2dd..863c50b64d 100644
--- a/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.h
+++ b/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.h
@@ -1,179 +1,179 @@
 /*===================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center,
 Division of Medical and Biological Informatics.
 All rights reserved.
 
 This software is distributed WITHOUT ANY WARRANTY; without
 even the implied warranty of MERCHANTABILITY or FITNESS FOR
 A PARTICULAR PURPOSE.
 
 See LICENSE.txt or http://www.mitk.org for details.
 
 ===================================================================*/
 
 
 #ifndef _MITK_FiberBundle_H
 #define _MITK_FiberBundle_H
 
 //includes for MITK datastructure
 #include <mitkBaseData.h>
 #include <MitkFiberTrackingExports.h>
 #include <mitkImage.h>
 #include <mitkDataStorage.h>
 #include <mitkPlanarFigure.h>
 #include <mitkPixelTypeTraits.h>
 #include <mitkPlanarFigureComposite.h>
 
 
 //includes storing fiberdata
 #include <vtkSmartPointer.h>
 #include <vtkPolyData.h>
 #include <vtkPoints.h>
 #include <vtkDataSet.h>
 #include <vtkTransform.h>
 #include <vtkFloatArray.h>
 
 
 namespace mitk {
 
 /**
    * \brief Base Class for Fiber Bundles;   */
 class MITKFIBERTRACKING_EXPORT FiberBundle : public BaseData
 {
 public:
 
     typedef itk::Image<unsigned char, 3> ItkUcharImgType;
 
     // fiber colorcodings
     static const char* FIBER_ID_ARRAY;
 
     virtual void UpdateOutputInformation() override;
     virtual void SetRequestedRegionToLargestPossibleRegion() override;
     virtual bool RequestedRegionIsOutsideOfTheBufferedRegion() override;
     virtual bool VerifyRequestedRegion() override;
     virtual void SetRequestedRegion(const itk::DataObject*) override;
 
     mitkClassMacro( FiberBundle, BaseData )
     itkFactorylessNewMacro(Self)
     itkCloneMacro(Self)
     mitkNewMacro1Param(Self, vtkSmartPointer<vtkPolyData>) // custom constructor
 
     // colorcoding related methods
     void ColorFibersByFiberWeights(bool opacity, bool normalize);
     void ColorFibersByCurvature(bool opacity, bool normalize);
     void ColorFibersByScalarMap(mitk::Image::Pointer, bool opacity, bool normalize);
     template <typename TPixel>
     void ColorFibersByScalarMap(const mitk::PixelType pixelType, mitk::Image::Pointer, bool opacity, bool normalize);
     void ColorFibersByOrientation();
     void SetFiberOpacity(vtkDoubleArray *FAValArray);
     void ResetFiberOpacity();
     void SetFiberColors(vtkSmartPointer<vtkUnsignedCharArray> fiberColors);
     void SetFiberColors(float r, float g, float b, float alpha=255);
     vtkSmartPointer<vtkUnsignedCharArray> GetFiberColors() const { return m_FiberColors; }
 
     // fiber compression
     void Compress(float error = 0.0);
 
     // fiber resampling
     void ResampleSpline(float pointDistance=1);
     void ResampleSpline(float pointDistance, double tension, double continuity, double bias );
     void ResampleLinear(double pointDistance=1);
 
+    mitk::FiberBundle::Pointer FilterByWeights(float weight_thr, bool invert=false);
     bool RemoveShortFibers(float lengthInMM);
     bool RemoveLongFibers(float lengthInMM);
     bool ApplyCurvatureThreshold(float minRadius, bool deleteFibers);
     void MirrorFibers(unsigned int axis);
     void RotateAroundAxis(double x, double y, double z);
     void TranslateFibers(double x, double y, double z);
     void ScaleFibers(double x, double y, double z, bool subtractCenter=true);
     void TransformFibers(double rx, double ry, double rz, double tx, double ty, double tz);
     void RemoveDir(vnl_vector_fixed<double,3> dir, double threshold);
     itk::Point<float, 3> TransformPoint(vnl_vector_fixed< double, 3 > point, double rx, double ry, double rz, double tx, double ty, double tz);
     itk::Matrix< double, 3, 3 > TransformMatrix(itk::Matrix< double, 3, 3 > m, double rx, double ry, double rz);
 
     // add/subtract fibers
     FiberBundle::Pointer AddBundle(FiberBundle* fib);
+    mitk::FiberBundle::Pointer AddBundles(std::vector< mitk::FiberBundle::Pointer > fibs);
     FiberBundle::Pointer SubtractBundle(FiberBundle* fib);
 
     // fiber subset extraction
     FiberBundle::Pointer           ExtractFiberSubset(DataNode *roi, DataStorage* storage);
     std::vector<long>              ExtractFiberIdSubset(DataNode* roi, DataStorage* storage);
     FiberBundle::Pointer           ExtractFiberSubset(ItkUcharImgType* mask, bool anyPoint, bool invert=false, bool bothEnds=true, float fraction=0.0, bool do_resampling=true);
     FiberBundle::Pointer           RemoveFibersOutside(ItkUcharImgType* mask, bool invert=false);
-
-    vtkSmartPointer<vtkPolyData>    GeneratePolyDataByIds( std::vector<long> ); // TODO: make protected
-    void                            GenerateFiberIds(); // TODO: make protected
+    float                          GetOverlap(ItkUcharImgType* mask, bool do_resampling);
+    mitk::FiberBundle::Pointer     SubsampleFibers(float factor);
 
     // get/set data
     vtkSmartPointer<vtkFloatArray> GetFiberWeights() const { return m_FiberWeights; }
     float GetFiberWeight(unsigned int fiber) const;
     void SetFiberWeights(float newWeight);
     void SetFiberWeight(unsigned int fiber, float weight);
     void SetFiberWeights(vtkSmartPointer<vtkFloatArray> weights);
     void SetFiberPolyData(vtkSmartPointer<vtkPolyData>, bool updateGeometry = true);
     vtkSmartPointer<vtkPolyData> GetFiberPolyData() const;
     itkGetConstMacro( NumFibers, int)
     //itkGetMacro( FiberSampling, int)
     itkGetConstMacro( MinFiberLength, float )
     itkGetConstMacro( MaxFiberLength, float )
     itkGetConstMacro( MeanFiberLength, float )
     itkGetConstMacro( MedianFiberLength, float )
     itkGetConstMacro( LengthStDev, float )
     itkGetConstMacro( UpdateTime2D, itk::TimeStamp )
     itkGetConstMacro( UpdateTime3D, itk::TimeStamp )
     void RequestUpdate2D(){ m_UpdateTime2D.Modified(); }
     void RequestUpdate3D(){ m_UpdateTime3D.Modified(); }
     void RequestUpdate(){ m_UpdateTime2D.Modified(); m_UpdateTime3D.Modified(); }
 
     unsigned long GetNumberOfPoints() const;
 
     // copy fiber bundle
     mitk::FiberBundle::Pointer GetDeepCopy();
 
     // compare fiber bundles
     bool Equals(FiberBundle* fib, double eps=0.01);
 
     itkSetMacro( ReferenceGeometry, mitk::BaseGeometry::Pointer )
     itkGetConstMacro( ReferenceGeometry, mitk::BaseGeometry::Pointer )
 
 protected:
 
     FiberBundle( vtkPolyData* fiberPolyData = nullptr );
     virtual ~FiberBundle();
 
-    itk::Point<float, 3> GetItkPoint(double point[3]);
-
-    // calculate geometry from fiber extent
-    void UpdateFiberGeometry();
-
-    virtual void PrintSelf(std::ostream &os, itk::Indent indent) const override;
+    vtkSmartPointer<vtkPolyData>    GeneratePolyDataByIds(std::vector<long> fiberIds, vtkSmartPointer<vtkFloatArray> weights);
+    void                            GenerateFiberIds();
+    itk::Point<float, 3>            GetItkPoint(double point[3]);
+    void                            UpdateFiberGeometry();
+    virtual void                    PrintSelf(std::ostream &os, itk::Indent indent) const override;
 
 private:
 
     // actual fiber container
     vtkSmartPointer<vtkPolyData>  m_FiberPolyData;
 
     // contains fiber ids
     vtkSmartPointer<vtkDataSet>   m_FiberIdDataSet;
 
     int   m_NumFibers;
 
     vtkSmartPointer<vtkUnsignedCharArray> m_FiberColors;
     vtkSmartPointer<vtkFloatArray> m_FiberWeights;
     std::vector< float > m_FiberLengths;
     float   m_MinFiberLength;
     float   m_MaxFiberLength;
     float   m_MeanFiberLength;
     float   m_MedianFiberLength;
     float   m_LengthStDev;
     itk::TimeStamp m_UpdateTime2D;
     itk::TimeStamp m_UpdateTime3D;
     mitk::BaseGeometry::Pointer m_ReferenceGeometry;
 };
 
 } // namespace mitk
 
 #endif /*  _MITK_FiberBundle_H */
diff --git a/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkTrackvis.cpp b/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkTrackvis.cpp
index e501575e58..ce5b004615 100644
--- a/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkTrackvis.cpp
+++ b/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkTrackvis.cpp
@@ -1,240 +1,241 @@
 #include <mitkTrackvis.h>
 #include <vtkTransformPolyDataFilter.h>
 
 TrackVisFiberReader::TrackVisFiberReader()  { m_Filename = ""; m_FilePointer = nullptr; }
 
 TrackVisFiberReader::~TrackVisFiberReader() { if (m_FilePointer) fclose( m_FilePointer ); }
 
 
 // Create a TrackVis file and store standard metadata. The file is ready to append fibers.
 // ---------------------------------------------------------------------------------------
 short TrackVisFiberReader::create(string filename , const mitk::FiberBundle *fib, bool lps)
 {
-    // prepare the header
-    for(int i=0; i<3 ;i++)
+  // prepare the header
+  for(int i=0; i<3 ;i++)
+  {
+    if (fib->GetReferenceGeometry().IsNotNull())
     {
-        if (fib->GetReferenceGeometry().IsNotNull())
-        {
-            m_Header.dim[i]            = fib->GetReferenceGeometry()->GetExtent(i);
-            m_Header.voxel_size[i]     = fib->GetReferenceGeometry()->GetSpacing()[i];
-            m_Header.origin[i]         = fib->GetReferenceGeometry()->GetOrigin()[i];
-        }
-        else
-        {
-            m_Header.dim[i]            = fib->GetGeometry()->GetExtent(i);
-            m_Header.voxel_size[i]     = fib->GetGeometry()->GetSpacing()[i];
-            m_Header.origin[i]         = fib->GetGeometry()->GetOrigin()[i];
-        }
+      m_Header.dim[i]            = fib->GetReferenceGeometry()->GetExtent(i);
+      m_Header.voxel_size[i]     = fib->GetReferenceGeometry()->GetSpacing()[i];
+      m_Header.origin[i]         = fib->GetReferenceGeometry()->GetOrigin()[i];
     }
-    m_Header.n_scalars = 0;
-    m_Header.n_properties = 0;
-    if (lps)
-        sprintf(m_Header.voxel_order,"LPS");
     else
-        sprintf(m_Header.voxel_order,"RAS");
-    m_Header.image_orientation_patient[0] = 1.0;
-    m_Header.image_orientation_patient[1] = 0.0;
-    m_Header.image_orientation_patient[2] = 0.0;
-    m_Header.image_orientation_patient[3] = 0.0;
-    m_Header.image_orientation_patient[4] = 1.0;
-    m_Header.image_orientation_patient[5] = 0.0;
-    m_Header.pad1[0] = 0;
-    m_Header.pad1[1] = 0;
-    m_Header.pad2[0] = 0;
-    m_Header.pad2[1] = 0;
-    m_Header.invert_x = 0;
-    m_Header.invert_y = 0;
-    m_Header.invert_z = 0;
-    m_Header.swap_xy = 0;
-    m_Header.swap_yz = 0;
-    m_Header.swap_zx = 0;
-    m_Header.n_count = 0;
-    m_Header.version = 1;
-    m_Header.hdr_size = 1000;
-
-    // write the header to the file
-    m_FilePointer = fopen(filename.c_str(),"w+b");
-    if (m_FilePointer == nullptr)
     {
-        printf("[ERROR] Unable to create file '%s'\n",filename.c_str());
-        return 0;
+      m_Header.dim[i]            = fib->GetGeometry()->GetExtent(i);
+      m_Header.voxel_size[i]     = fib->GetGeometry()->GetSpacing()[i];
+      m_Header.origin[i]         = fib->GetGeometry()->GetOrigin()[i];
     }
-    sprintf(m_Header.id_string,"TRACK");
-    if (fwrite((char*)&m_Header, 1, 1000, m_FilePointer) != 1000)
-        MITK_ERROR << "TrackVis::create : Error occurding during writing fiber.";
+  }
+  m_Header.n_scalars = 0;
+  m_Header.n_properties = 0;
+  if (lps)
+    sprintf(m_Header.voxel_order,"LPS");
+  else
+    sprintf(m_Header.voxel_order,"RAS");
+  m_Header.image_orientation_patient[0] = 1.0;
+  m_Header.image_orientation_patient[1] = 0.0;
+  m_Header.image_orientation_patient[2] = 0.0;
+  m_Header.image_orientation_patient[3] = 0.0;
+  m_Header.image_orientation_patient[4] = 1.0;
+  m_Header.image_orientation_patient[5] = 0.0;
+  m_Header.pad1[0] = 0;
+  m_Header.pad1[1] = 0;
+  m_Header.pad2[0] = 0;
+  m_Header.pad2[1] = 0;
+  m_Header.invert_x = 0;
+  m_Header.invert_y = 0;
+  m_Header.invert_z = 0;
+  m_Header.swap_xy = 0;
+  m_Header.swap_yz = 0;
+  m_Header.swap_zx = 0;
+  m_Header.n_count = 0;
+  m_Header.version = 1;
+  m_Header.hdr_size = 1000;
+
+  // write the header to the file
+  m_FilePointer = fopen(filename.c_str(),"w+b");
+  if (m_FilePointer == nullptr)
+  {
+    printf("[ERROR] Unable to create file '%s'\n",filename.c_str());
+    return 0;
+  }
+  sprintf(m_Header.id_string,"TRACK");
+  if (fwrite((char*)&m_Header, 1, 1000, m_FilePointer) != 1000)
+    MITK_ERROR << "TrackVis::create : Error occurding during writing fiber.";
 
-    this->m_Filename = filename;
+  this->m_Filename = filename;
 
-    return 1;
+  return 1;
 }
 
 
 // Open an existing TrackVis file and read metadata information.
 // The file pointer is positiond at the beginning of fibers data
 // -------------------------------------------------------------
 short TrackVisFiberReader::open( string filename )
 {
-    m_FilePointer = fopen(filename.c_str(), "rb");
-    if (m_FilePointer == nullptr)
-    {
-        printf("[ERROR] Unable to open file '%s'\n",filename.c_str());
-        return 0;
-    }
-    this->m_Filename = filename;
+  m_FilePointer = fopen(filename.c_str(), "rb");
+  if (m_FilePointer == nullptr)
+  {
+    printf("[ERROR] Unable to open file '%s'\n",filename.c_str());
+    return 0;
+  }
+  this->m_Filename = filename;
 
-    return fread((char*)(&m_Header), 1, 1000, m_FilePointer);
+  return fread((char*)(&m_Header), 1, 1000, m_FilePointer);
 }
 
 
 
 // Append a fiber to the file
 // --------------------------
 short TrackVisFiberReader::append(const mitk::FiberBundle *fib)
 {
-    vtkPolyData* poly = fib->GetFiberPolyData();
-    for (int i=0; i<fib->GetNumFibers(); i++)
+  vtkPolyData* poly = fib->GetFiberPolyData();
+  for (int i=0; i<fib->GetNumFibers(); i++)
+  {
+    vtkCell* cell = poly->GetCell(i);
+    int numPoints = cell->GetNumberOfPoints();
+    vtkPoints* points = cell->GetPoints();
+
+    unsigned int     numSaved, pos = 0;
+    //float* tmp = new float[3*maxSteps];
+    std::vector< float > tmp;
+    tmp.reserve(3*numPoints);
+
+    numSaved = numPoints;
+    for(unsigned int i=0; i<numSaved ;i++)
     {
-        vtkCell* cell = poly->GetCell(i);
-        int numPoints = cell->GetNumberOfPoints();
-        vtkPoints* points = cell->GetPoints();
-
-        unsigned int     numSaved, pos = 0;
-        //float* tmp = new float[3*maxSteps];
-        std::vector< float > tmp;
-        tmp.reserve(3*numPoints);
-
-        numSaved = numPoints;
-        for(unsigned int i=0; i<numSaved ;i++)
-        {
-            double* p = points->GetPoint(i);
-
-            tmp[pos++] = p[0];
-            tmp[pos++] = p[1];
-            tmp[pos++] = p[2];
-        }
-
-        // write the coordinates to the file
-        if ( fwrite((char*)&numSaved, 1, 4, m_FilePointer) != 4 )
-        {
-            printf( "[ERROR] Problems saving the fiber!\n" );
-            return 1;
-        }
-        if ( fwrite((char*)&(tmp.front()), 1, 4*pos, m_FilePointer) != 4*pos )
-        {
-            printf( "[ERROR] Problems saving the fiber!\n" );
-            return 1;
-        }
+      double* p = points->GetPoint(i);
+
+      tmp[pos++] = p[0];
+      tmp[pos++] = p[1];
+      tmp[pos++] = p[2];
     }
 
-    return 0;
+    // write the coordinates to the file
+    if ( fwrite((char*)&numSaved, 1, 4, m_FilePointer) != 4 )
+    {
+      printf( "[ERROR] Problems saving the fiber!\n" );
+      return 1;
+    }
+    if ( fwrite((char*)&(tmp.front()), 1, 4*pos, m_FilePointer) != 4*pos )
+    {
+      printf( "[ERROR] Problems saving the fiber!\n" );
+      return 1;
+    }
+  }
+
+  return 0;
 }
 
 //// Read one fiber from the file
 //// ----------------------------
 short TrackVisFiberReader::read( mitk::FiberBundle* fib )
 {
-    int numPoints;
-    vtkSmartPointer<vtkPoints> vtkNewPoints = vtkSmartPointer<vtkPoints>::New();
-    vtkSmartPointer<vtkCellArray> vtkNewCells = vtkSmartPointer<vtkCellArray>::New();
+  int numPoints;
+  vtkSmartPointer<vtkPoints> vtkNewPoints = vtkSmartPointer<vtkPoints>::New();
+  vtkSmartPointer<vtkCellArray> vtkNewCells = vtkSmartPointer<vtkCellArray>::New();
 
-    while (fread((char*)&numPoints, 1, 4, m_FilePointer)==4)
+  while (fread((char*)&numPoints, 1, 4, m_FilePointer)==4)
+  {
+    if ( numPoints <= 0 )
     {
-        if ( numPoints <= 0 )
-        {
-            printf( "[ERROR] Trying to read a fiber with %d points!\n", numPoints );
-            return -1;
-        }
-        vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New();
-
-        float tmp[3];
-        for(int i=0; i<numPoints; i++)
-        {
-            if (fread((char*)tmp, 1, 12, m_FilePointer) == 0)
-                MITK_ERROR << "TrackVis::read: Error during read.";
-
-            vtkIdType id = vtkNewPoints->InsertNextPoint(tmp);
-            container->GetPointIds()->InsertNextId(id);
-        }
-        vtkNewCells->InsertNextCell(container);
+      printf( "[ERROR] Trying to read a fiber with %d points!\n", numPoints );
+      return -1;
     }
+    vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New();
 
-    vtkSmartPointer<vtkPolyData> fiberPolyData = vtkSmartPointer<vtkPolyData>::New();
-    fiberPolyData->SetPoints(vtkNewPoints);
-    fiberPolyData->SetLines(vtkNewCells);
-
-    MITK_INFO << "Coordinate convention: " << m_Header.voxel_order;
-
-    mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New();
-    vtkSmartPointer< vtkMatrix4x4 > matrix = vtkSmartPointer< vtkMatrix4x4 >::New();
-    matrix->Identity();
-
-    if (m_Header.voxel_order[0]=='R')
-        matrix->SetElement(0,0,-matrix->GetElement(0,0));
-    if (m_Header.voxel_order[1]=='A')
-        matrix->SetElement(1,1,-matrix->GetElement(1,1));
-    if (m_Header.voxel_order[2]=='I')
-        matrix->SetElement(2,2,-matrix->GetElement(2,2));
-
-    geometry->SetIndexToWorldTransformByVtkMatrix(matrix);
-
-    vtkSmartPointer<vtkTransformPolyDataFilter> transformFilter = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
-    transformFilter->SetInputData(fiberPolyData);
-    transformFilter->SetTransform(geometry->GetVtkTransform());
-    transformFilter->Update();
-    fib->SetFiberPolyData(transformFilter->GetOutput());
-
-    mitk::Point3D origin;
-    origin[0]=m_Header.origin[0];
-    origin[1]=m_Header.origin[1];
-    origin[2]=m_Header.origin[2];
-    geometry->SetOrigin(origin);
-
-    mitk::Vector3D spacing;
-    spacing[0]=m_Header.voxel_size[0];
-    spacing[1]=m_Header.voxel_size[1];
-    spacing[2]=m_Header.voxel_size[2];
-    geometry->SetSpacing(spacing);
+    float tmp[3];
+    for(int i=0; i<numPoints; i++)
+    {
+      if (fread((char*)tmp, 1, 12, m_FilePointer) == 0)
+        MITK_ERROR << "TrackVis::read: Error during read.";
 
+      vtkIdType id = vtkNewPoints->InsertNextPoint(tmp);
+      container->GetPointIds()->InsertNextId(id);
+    }
+    vtkNewCells->InsertNextCell(container);
+  }
+
+  vtkSmartPointer<vtkPolyData> fiberPolyData = vtkSmartPointer<vtkPolyData>::New();
+  fiberPolyData->SetPoints(vtkNewPoints);
+  fiberPolyData->SetLines(vtkNewCells);
+
+  //    MITK_INFO << "Coordinate convention: " << m_Header.voxel_order;
+
+  mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New();
+  vtkSmartPointer< vtkMatrix4x4 > matrix = vtkSmartPointer< vtkMatrix4x4 >::New();
+  matrix->Identity();
+
+  if (m_Header.voxel_order[0]=='R')
+    matrix->SetElement(0,0,-matrix->GetElement(0,0));
+  if (m_Header.voxel_order[1]=='A')
+    matrix->SetElement(1,1,-matrix->GetElement(1,1));
+  if (m_Header.voxel_order[2]=='I')
+    matrix->SetElement(2,2,-matrix->GetElement(2,2));
+
+  geometry->SetIndexToWorldTransformByVtkMatrix(matrix);
+
+  vtkSmartPointer<vtkTransformPolyDataFilter> transformFilter = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
+  transformFilter->SetInputData(fiberPolyData);
+  transformFilter->SetTransform(geometry->GetVtkTransform());
+  transformFilter->Update();
+  fib->SetFiberPolyData(transformFilter->GetOutput());
+
+  mitk::Point3D origin;
+  origin[0]=m_Header.origin[0];
+  origin[1]=m_Header.origin[1];
+  origin[2]=m_Header.origin[2];
+  geometry->SetOrigin(origin);
+
+  mitk::Vector3D spacing;
+  spacing[0]=m_Header.voxel_size[0];
+  spacing[1]=m_Header.voxel_size[1];
+  spacing[2]=m_Header.voxel_size[2];
+
+  if (spacing[0]>0 && spacing[1]>0 && spacing[2]>0 && m_Header.dim[0]>0 && m_Header.dim[1]>0 && m_Header.dim[2]>0)
+  {
+    geometry->SetSpacing(spacing);
     geometry->SetExtentInMM(0, m_Header.voxel_size[0]*m_Header.dim[0]);
     geometry->SetExtentInMM(1, m_Header.voxel_size[1]*m_Header.dim[1]);
     geometry->SetExtentInMM(2, m_Header.voxel_size[2]*m_Header.dim[2]);
-
     fib->SetReferenceGeometry(dynamic_cast<mitk::BaseGeometry*>(geometry.GetPointer()));
-
-    return numPoints;
+  }
+  return numPoints;
 }
 
 
 
 // Update the field in the header to the new FIBER TOTAL.
 // ------------------------------------------------------
 void TrackVisFiberReader::updateTotal( int totFibers )
 {
-    fseek(m_FilePointer, 1000-12, SEEK_SET);
-    if (fwrite((char*)&totFibers, 1, 4, m_FilePointer) != 4)
-        MITK_ERROR << "[ERROR] Problems saving the fiber!";
+  fseek(m_FilePointer, 1000-12, SEEK_SET);
+  if (fwrite((char*)&totFibers, 1, 4, m_FilePointer) != 4)
+    MITK_ERROR << "[ERROR] Problems saving the fiber!";
 }
 
 
 void TrackVisFiberReader::writeHdr()
 {
-    fseek(m_FilePointer, 0, SEEK_SET);
-    if (fwrite((char*)&m_Header, 1, 1000, m_FilePointer) != 1000)
-        MITK_ERROR << "[ERROR] Problems saving the fiber!";
+  fseek(m_FilePointer, 0, SEEK_SET);
+  if (fwrite((char*)&m_Header, 1, 1000, m_FilePointer) != 1000)
+    MITK_ERROR << "[ERROR] Problems saving the fiber!";
 }
 
 
 // Close the TrackVis file, but keep the metadata in the header.
 // -------------------------------------------------------------
 void TrackVisFiberReader::close()
 {
-    fclose(m_FilePointer);
-    m_FilePointer = nullptr;
+  fclose(m_FilePointer);
+  m_FilePointer = nullptr;
 }
 
 bool TrackVisFiberReader::IsTransformValid()
 {
-    if (fabs(m_Header.image_orientation_patient[0])<=0.001 || fabs(m_Header.image_orientation_patient[3])<=0.001 || fabs(m_Header.image_orientation_patient[5])<=0.001)
-        return false;
-    return true;
+  if (fabs(m_Header.image_orientation_patient[0])<=0.001 || fabs(m_Header.image_orientation_patient[3])<=0.001 || fabs(m_Header.image_orientation_patient[5])<=0.001)
+    return false;
+  return true;
 }
diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FitFibersToImage.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FitFibersToImage.cpp
index e58629356e..421f49ffea 100755
--- a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FitFibersToImage.cpp
+++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FitFibersToImage.cpp
@@ -1,203 +1,217 @@
 /*===================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center,
 Division of Medical and Biological Informatics.
 All rights reserved.
 
 This software is distributed WITHOUT ANY WARRANTY; without
 even the implied warranty of MERCHANTABILITY or FITNESS FOR
 A PARTICULAR PURPOSE.
 
 See LICENSE.txt or http://www.mitk.org for details.
 
 ===================================================================*/
 
 #include <mitkBaseData.h>
 #include <mitkImageCast.h>
 #include <mitkImageToItk.h>
 #include <metaCommand.h>
 #include <mitkCommandLineParser.h>
 #include <usAny.h>
 #include <mitkIOUtil.h>
 #include <itksys/SystemTools.hxx>
 #include <itkDirectory.h>
 #include <mitkFiberBundle.h>
 #include <mitkPreferenceListReaderOptionsFunctor.h>
 #include <itkImageFileWriter.h>
 #include <mitkPeakImage.h>
 #include <itkFitFibersToImageFilter.h>
 
 using namespace std;
 typedef itksys::SystemTools ist;
 typedef itk::Point<float, 4> PointType4;
 typedef itk::Image< float, 4 >  PeakImgType;
 
 std::vector< string > get_file_list(const std::string& path)
 {
   std::vector< string > file_list;
   itk::Directory::Pointer dir = itk::Directory::New();
 
   if (dir->Load(path.c_str()))
   {
     int n = dir->GetNumberOfFiles();
     for (int r = 0; r < n; r++)
     {
       const char *filename = dir->GetFile(r);
       std::string ext = ist::GetFilenameExtension(filename);
       if (ext==".fib" || ext==".trk")
         file_list.push_back(path + '/' + filename);
     }
   }
   return file_list;
 }
 
 /*!
 \brief Fits the tractogram to the input peak image by assigning a weight to each fiber (similar to https://doi.org/10.1016/j.neuroimage.2015.06.092).
 */
 int main(int argc, char* argv[])
 {
   mitkCommandLineParser parser;
 
   parser.setTitle("Fit Fibers To Image");
   parser.setCategory("Fiber Tracking and Processing Methods");
   parser.setDescription("Assigns a weight to each fiber in order to optimally explain the input peak image");
   parser.setContributor("MIC");
 
   parser.setArgumentPrefix("--", "-");
   parser.addArgument("", "i1", mitkCommandLineParser::StringList, "Input tractograms:", "input tractograms (.fib, vtk ascii file format)", us::Any(), false);
   parser.addArgument("", "i2", mitkCommandLineParser::InputFile, "Input peaks:", "input peak image", us::Any(), false);
   parser.addArgument("", "o", mitkCommandLineParser::OutputDirectory, "Output:", "output root", us::Any(), false);
 
   parser.addArgument("max_iter", "", mitkCommandLineParser::Int, "Max. iterations:", "maximum number of optimizer iterations", 20);
   parser.addArgument("bundle_based", "", mitkCommandLineParser::Bool, "Bundle based fit:", "fit one weight per input tractogram/bundle, not for each fiber", false);
   parser.addArgument("min_g", "", mitkCommandLineParser::Float, "Min. g:", "lower termination threshold for gradient magnitude", 1e-5);
   parser.addArgument("lambda", "", mitkCommandLineParser::Float, "Lambda:", "modifier for regularization", 0.1);
-  parser.addArgument("save_res", "", mitkCommandLineParser::Bool, "Residuals:", "save residual images", false);
+  parser.addArgument("save_res", "", mitkCommandLineParser::Bool, "Save Residuals:", "save residual images", false);
+  parser.addArgument("save_weights", "", mitkCommandLineParser::Bool, "Save Weights:", "save fiber weights in a separate text file", false);
   parser.addArgument("dont_filter_outliers", "", mitkCommandLineParser::Bool, "Don't filter outliers:", "don't perform second optimization run with an upper weight bound based on the first weight estimation (95% quantile)", false);
 
   map<string, us::Any> parsedArgs = parser.parseArguments(argc, argv);
   if (parsedArgs.size()==0)
     return EXIT_FAILURE;
 
   mitkCommandLineParser::StringContainerType fib_files = us::any_cast<mitkCommandLineParser::StringContainerType>(parsedArgs["i1"]);
   string peak_file_name = us::any_cast<string>(parsedArgs["i2"]);
   string outRoot = us::any_cast<string>(parsedArgs["o"]);
 
   bool single_fib = true;
   if (parsedArgs.count("bundle_based"))
     single_fib = !us::any_cast<bool>(parsedArgs["bundle_based"]);
 
   bool save_residuals = false;
   if (parsedArgs.count("save_res"))
     save_residuals = us::any_cast<bool>(parsedArgs["save_res"]);
 
+  bool save_weights = false;
+  if (parsedArgs.count("save_weights"))
+    save_weights = us::any_cast<bool>(parsedArgs["save_weights"]);
+
   int max_iter = 20;
   if (parsedArgs.count("max_iter"))
     max_iter = us::any_cast<int>(parsedArgs["max_iter"]);
 
   float g_tol = 1e-5;
   if (parsedArgs.count("min_g"))
     g_tol = us::any_cast<float>(parsedArgs["min_g"]);
 
   float lambda = 0.1;
   if (parsedArgs.count("lambda"))
     lambda = us::any_cast<float>(parsedArgs["lambda"]);
 
   bool filter_outliers = true;
   if (parsedArgs.count("dont_filter_outliers"))
     filter_outliers = !us::any_cast<bool>(parsedArgs["dont_filter_outliers"]);
 
   try
   {
     std::vector< mitk::FiberBundle::Pointer > input_tracts;
 
     mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor({"Peak Image", "Fiberbundles"}, {});
     mitk::Image::Pointer inputImage = dynamic_cast<mitk::PeakImage*>(mitk::IOUtil::Load(peak_file_name, &functor)[0].GetPointer());
 
     typedef mitk::ImageToItk< PeakImgType > CasterType;
     CasterType::Pointer caster = CasterType::New();
     caster->SetInput(inputImage);
     caster->Update();
     PeakImgType::Pointer peak_image = caster->GetOutput();
 
     std::vector< std::string > fib_names;
     for (auto item : fib_files)
     {
       if ( ist::FileIsDirectory(item) )
       {
         for ( auto fibFile : get_file_list(item) )
         {
           mitk::FiberBundle::Pointer inputTractogram = dynamic_cast<mitk::FiberBundle*>(mitk::IOUtil::Load(fibFile)[0].GetPointer());
           if (inputTractogram.IsNull())
             continue;
           input_tracts.push_back(inputTractogram);
           fib_names.push_back(fibFile);
         }
       }
       else
       {
         mitk::FiberBundle::Pointer inputTractogram = dynamic_cast<mitk::FiberBundle*>(mitk::IOUtil::Load(item)[0].GetPointer());
         if (inputTractogram.IsNull())
           continue;
         input_tracts.push_back(inputTractogram);
         fib_names.push_back(item);
       }
     }
 
     itk::FitFibersToImageFilter::Pointer fitter = itk::FitFibersToImageFilter::New();
     fitter->SetPeakImage(peak_image);
     fitter->SetTractograms(input_tracts);
     fitter->SetFitIndividualFibers(single_fib);
     fitter->SetMaxIterations(max_iter);
     fitter->SetGradientTolerance(g_tol);
     fitter->SetLambda(lambda);
     fitter->SetFilterOutliers(filter_outliers);
     fitter->Update();
 
     if (save_residuals)
     {
       itk::ImageFileWriter< PeakImgType >::Pointer writer = itk::ImageFileWriter< PeakImgType >::New();
       writer->SetInput(fitter->GetFittedImage());
       writer->SetFileName(outRoot + "fitted_image.nrrd");
       writer->Update();
 
       writer->SetInput(fitter->GetResidualImage());
       writer->SetFileName(outRoot + "residual_image.nrrd");
       writer->Update();
 
       writer->SetInput(fitter->GetOverexplainedImage());
       writer->SetFileName(outRoot + "overexplained_image.nrrd");
       writer->Update();
 
       writer->SetInput(fitter->GetUnderexplainedImage());
       writer->SetFileName(outRoot + "underexplained_image.nrrd");
       writer->Update();
     }
 
     std::vector< mitk::FiberBundle::Pointer > output_tracts = fitter->GetTractograms();
     for (unsigned int bundle=0; bundle<output_tracts.size(); bundle++)
     {
       std::string name = fib_names.at(bundle);
       name = ist::GetFilenameWithoutExtension(name);
       mitk::IOUtil::Save(output_tracts.at(bundle), outRoot + name + "_fitted.fib");
+
+      if (save_weights)
+      {
+        ofstream logfile;
+        logfile.open (outRoot + name + "_weights.txt");
+        for (int f=0; f<output_tracts.at(bundle)->GetNumFibers(); ++f)
+          logfile << output_tracts.at(bundle)->GetFiberWeight(f) << "\n";
+        logfile.close();
+      }
     }
   }
   catch (itk::ExceptionObject e)
   {
     std::cout << e;
     return EXIT_FAILURE;
   }
   catch (std::exception e)
   {
     std::cout << e.what();
     return EXIT_FAILURE;
   }
   catch (...)
   {
     std::cout << "ERROR!?!";
     return EXIT_FAILURE;
   }
   return EXIT_SUCCESS;
 }
diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/AnchorBasedScoring.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/AnchorBasedScoring.cpp
new file mode 100755
index 0000000000..16e127144f
--- /dev/null
+++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/AnchorBasedScoring.cpp
@@ -0,0 +1,444 @@
+/*===================================================================
+
+The Medical Imaging Interaction Toolkit (MITK)
+
+Copyright (c) German Cancer Research Center,
+Division of Medical and Biological Informatics.
+All rights reserved.
+
+This software is distributed WITHOUT ANY WARRANTY; without
+even the implied warranty of MERCHANTABILITY or FITNESS FOR
+A PARTICULAR PURPOSE.
+
+See LICENSE.txt or http://www.mitk.org for details.
+
+===================================================================*/
+
+#include <mitkBaseData.h>
+#include <mitkImageCast.h>
+#include <mitkImageToItk.h>
+#include <metaCommand.h>
+#include <mitkCommandLineParser.h>
+#include <usAny.h>
+#include <mitkIOUtil.h>
+#include <itksys/SystemTools.hxx>
+#include <itkDirectory.h>
+#include <mitkFiberBundle.h>
+#include <mitkPreferenceListReaderOptionsFunctor.h>
+#include <itkImageFileWriter.h>
+#include <mitkPeakImage.h>
+#include <itkFitFibersToImageFilter.h>
+#include <boost/lexical_cast.hpp>
+#include <itkTractDensityImageFilter.h>
+
+using namespace std;
+typedef itksys::SystemTools ist;
+typedef itk::Point<float, 4> PointType4;
+typedef itk::Image< float, 4 >  PeakImgType;
+typedef itk::Image< unsigned char, 3 >  ItkUcharImageType;
+
+std::vector< string > get_file_list(const std::string& path, std::vector< string > extensions={".fib", ".trk"})
+{
+  std::vector< string > file_list;
+  itk::Directory::Pointer dir = itk::Directory::New();
+
+  if (dir->Load(path.c_str()))
+  {
+    int n = dir->GetNumberOfFiles();
+    for (int r = 0; r < n; r++)
+    {
+      const char *filename = dir->GetFile(r);
+      std::string ext = ist::GetFilenameExtension(filename);
+      for (auto e : extensions)
+      {
+        if (ext==e)
+        {
+          file_list.push_back(path + '/' + filename);
+          break;
+        }
+      }
+    }
+  }
+  return file_list;
+}
+
+std::vector< mitk::FiberBundle::Pointer > CombineTractograms(std::vector< mitk::FiberBundle::Pointer > reference, std::vector< mitk::FiberBundle::Pointer > candidates, int skip=-1)
+{
+  std::vector< mitk::FiberBundle::Pointer > fib;
+  for (auto f : reference)
+    fib.push_back(f);
+
+  int c = 0;
+  for (auto f : candidates)
+  {
+    if (c!=skip)
+      fib.push_back(f);
+    ++c;
+  }
+
+  return fib;
+}
+
+/*!
+\brief Fits the tractogram to the input peak image by assigning a weight to each fiber (similar to https://doi.org/10.1016/j.neuroimage.2015.06.092).
+*/
+int main(int argc, char* argv[])
+{
+  mitkCommandLineParser parser;
+
+  parser.setTitle("Anchor Based Scoring");
+  parser.setCategory("Fiber Tracking Evaluation");
+  parser.setDescription("");
+  parser.setContributor("MIC");
+
+  parser.setArgumentPrefix("--", "-");
+  parser.addArgument("", "i1", mitkCommandLineParser::InputFile, "Anchor tractogram:", "anchor tracts in one tractogram file", us::Any(), false);
+  parser.addArgument("", "i2", mitkCommandLineParser::InputFile, "Input peaks:", "input peak image", us::Any(), false);
+  parser.addArgument("", "i3", mitkCommandLineParser::InputFile, "Candidate folder:", "folder containing all candidate tracts (separate files)", us::Any(), false);
+  parser.addArgument("", "o", mitkCommandLineParser::OutputDirectory, "Output folder:", "output folder", us::Any(), false);
+
+  parser.addArgument("reference_mask_folder", "", mitkCommandLineParser::String, "Reference Mask Folder:", "reference tract masks for accuracy evaluation");
+  parser.addArgument("mask", "", mitkCommandLineParser::InputFile, "Mask image:", "scoring is only performed inside the mask image");
+  parser.addArgument("greedy_add", "", mitkCommandLineParser::Bool, "Greedy:", "if enabled, the candidate tracts are not jointly fitted to the residual image but one after the other employing a greedy scheme", false);
+  parser.addArgument("lambda", "", mitkCommandLineParser::Float, "Lambda:", "modifier for regularization", 0.1);
+  parser.addArgument("dont_filter_outliers", "", mitkCommandLineParser::Bool, "Don't filter outliers:", "don't perform second optimization run with an upper weight bound based on the first weight estimation (95% quantile)", false);
+
+  map<string, us::Any> parsedArgs = parser.parseArguments(argc, argv);
+  if (parsedArgs.size()==0)
+    return EXIT_FAILURE;
+
+  string anchors_file = us::any_cast<string>(parsedArgs["i1"]);
+  string peak_file_name = us::any_cast<string>(parsedArgs["i2"]);
+  string candidate_folder = us::any_cast<string>(parsedArgs["i3"]);
+  string out_folder = us::any_cast<string>(parsedArgs["o"]);
+
+  bool greedy_add = false;
+  if (parsedArgs.count("greedy_add"))
+    greedy_add = us::any_cast<bool>(parsedArgs["greedy_add"]);
+
+  float lambda = 0.1;
+  if (parsedArgs.count("lambda"))
+    lambda = us::any_cast<float>(parsedArgs["lambda"]);
+
+  bool filter_outliers = true;
+  if (parsedArgs.count("dont_filter_outliers"))
+    filter_outliers = !us::any_cast<bool>(parsedArgs["dont_filter_outliers"]);
+
+  string mask_file = "";
+  if (parsedArgs.count("mask"))
+    mask_file = us::any_cast<string>(parsedArgs["mask"]);
+
+  string reference_mask_folder = "";
+  if (parsedArgs.count("reference_mask_folder"))
+    reference_mask_folder = us::any_cast<string>(parsedArgs["reference_mask_folder"]);
+
+  try
+  {
+    itk::TimeProbe clock;
+    clock.Start();
+
+    MITK_INFO << "Creating directory structure";
+    if (ist::PathExists(out_folder))
+      ist::RemoveADirectory(out_folder);
+    ist::MakeDirectory(out_folder);
+
+    MITK_INFO << "Loading data";
+
+    streambuf *old = cout.rdbuf(); // <-- save
+    stringstream ss;
+    std::cout.rdbuf (ss.rdbuf());       // <-- redirect
+
+    ofstream logfile;
+    logfile.open (out_folder + "log.txt");
+
+    itk::ImageFileWriter< PeakImgType >::Pointer peak_image_writer = itk::ImageFileWriter< PeakImgType >::New();
+    mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor({"Peak Image", "Fiberbundles"}, {});
+    mitk::Image::Pointer inputImage = dynamic_cast<mitk::PeakImage*>(mitk::IOUtil::Load(peak_file_name, &functor)[0].GetPointer());
+
+    float minSpacing = 1;
+    if(inputImage->GetGeometry()->GetSpacing()[0]<inputImage->GetGeometry()->GetSpacing()[1] && inputImage->GetGeometry()->GetSpacing()[0]<inputImage->GetGeometry()->GetSpacing()[2])
+      minSpacing = inputImage->GetGeometry()->GetSpacing()[0];
+    else if (inputImage->GetGeometry()->GetSpacing()[1] < inputImage->GetGeometry()->GetSpacing()[2])
+      minSpacing = inputImage->GetGeometry()->GetSpacing()[1];
+    else
+      minSpacing = inputImage->GetGeometry()->GetSpacing()[2];
+
+    // Load mask file. Fit is only performed inside the mask
+    itk::FitFibersToImageFilter::UcharImgType::Pointer mask = nullptr;
+    if (mask_file.compare("")!=0)
+    {
+      mitk::Image::Pointer mitk_mask = dynamic_cast<mitk::Image*>(mitk::IOUtil::Load(mask_file)[0].GetPointer());
+      mitk::CastToItkImage(mitk_mask, mask);
+    }
+
+    // Load masks covering the true positives for evaluation purposes
+    std::vector< string > reference_mask_filenames;
+    std::vector< itk::FitFibersToImageFilter::UcharImgType::Pointer > reference_masks;
+    if (reference_mask_folder.compare("")!=0)
+    {
+      reference_mask_filenames = get_file_list(reference_mask_folder, {".nii", ".nii.gz", ".nrrd"});
+      for (auto filename : reference_mask_filenames)
+      {
+        itk::FitFibersToImageFilter::UcharImgType::Pointer ref_mask = nullptr;
+        mitk::Image::Pointer ref_mitk_mask = dynamic_cast<mitk::Image*>(mitk::IOUtil::Load(filename)[0].GetPointer());
+        mitk::CastToItkImage(ref_mitk_mask, ref_mask);
+        reference_masks.push_back(ref_mask);
+      }
+    }
+
+    // Load peak image
+    typedef mitk::ImageToItk< PeakImgType > CasterType;
+    CasterType::Pointer caster = CasterType::New();
+    caster->SetInput(inputImage);
+    caster->Update();
+    PeakImgType::Pointer peak_image = caster->GetOutput();
+
+    // Load all candidate tracts
+    std::vector< mitk::FiberBundle::Pointer > input_candidates;
+    std::vector< string > candidate_tract_files = get_file_list(candidate_folder);
+    for (string f : candidate_tract_files)
+    {
+      mitk::FiberBundle::Pointer fib = dynamic_cast<mitk::FiberBundle*>(mitk::IOUtil::Load(f)[0].GetPointer());
+      if (fib.IsNull())
+        continue;
+      if (fib->GetNumFibers()<=0)
+        return 0;
+      fib->ResampleLinear(minSpacing/10.0);
+      input_candidates.push_back(fib);
+    }
+    std::cout.rdbuf (old);              // <-- restore
+
+    double rmse = 0.0;
+    int iteration = 0;
+    std::string name = "NOANCHOR";
+    // Load reference tractogram consisting of all known tracts
+    std::vector< mitk::FiberBundle::Pointer > input_reference;
+    mitk::FiberBundle::Pointer anchor_tractogram = dynamic_cast<mitk::FiberBundle*>(mitk::IOUtil::Load(anchors_file)[0].GetPointer());
+    if ( !(anchor_tractogram.IsNull() || anchor_tractogram->GetNumFibers()==0) )
+    {
+      streambuf *old = cout.rdbuf(); // <-- save
+      stringstream ss;
+      std::cout.rdbuf (ss.rdbuf());       // <-- redirect
+      anchor_tractogram->ResampleLinear(minSpacing/10.0);
+      std::cout.rdbuf (old);              // <-- restore
+      input_reference.push_back(anchor_tractogram);
+
+      // Fit known tracts to peak image to obtain underexplained image
+      MITK_INFO << "Fit anchor tracts";
+      itk::FitFibersToImageFilter::Pointer fitter = itk::FitFibersToImageFilter::New();
+      fitter->SetTractograms(input_reference);
+      fitter->SetLambda(lambda);
+      fitter->SetFilterOutliers(filter_outliers);
+      fitter->SetPeakImage(peak_image);
+      fitter->SetVerbose(true);
+      fitter->SetResampleFibers(false);
+      fitter->SetMaskImage(mask);
+      fitter->Update();
+      rmse = fitter->GetRMSE();
+
+      name = ist::GetFilenameWithoutExtension(anchors_file);
+      mitk::FiberBundle::Pointer anchor_tracts = fitter->GetTractograms().at(0);
+      anchor_tracts->SetFiberColors(255,255,255);
+      mitk::IOUtil::Save(anchor_tracts, out_folder + "0_" + name + ".fib");
+
+      peak_image = fitter->GetUnderexplainedImage();
+      peak_image_writer->SetInput(peak_image);
+      peak_image_writer->SetFileName(out_folder + boost::lexical_cast<string>(iteration) + "_" + name + ".nrrd");
+      peak_image_writer->Update();
+    }
+
+    if (!greedy_add)
+    {
+      MITK_INFO << "Fit candidate tracts";
+      itk::FitFibersToImageFilter::Pointer fitter = itk::FitFibersToImageFilter::New();
+      fitter->SetLambda(lambda);
+      fitter->SetFilterOutliers(filter_outliers);
+      fitter->SetVerbose(true);
+      fitter->SetPeakImage(peak_image);
+      fitter->SetResampleFibers(false);
+      fitter->SetMaskImage(mask);
+      fitter->SetTractograms(input_candidates);
+      fitter->Update();
+      vnl_vector<double> rms_diff = fitter->GetRmsDiffPerBundle();
+
+      vnl_vector<double> log_rms_diff = rms_diff-rms_diff.min_value() + 1;
+      log_rms_diff = log_rms_diff.apply(std::log);
+      log_rms_diff /= log_rms_diff.max_value();
+      int c = 0;
+      for (auto fib : input_candidates)
+      {
+        fib->SetFiberWeights( log_rms_diff[c] );
+        fib->ColorFibersByFiberWeights(false, true);
+
+        string bundle_name = ist::GetFilenameWithoutExtension(candidate_tract_files.at(c));
+
+        streambuf *old = cout.rdbuf(); // <-- save
+        stringstream ss;
+        std::cout.rdbuf (ss.rdbuf());       // <-- redirect
+        mitk::IOUtil::Save(fib, out_folder + boost::lexical_cast<string>((int)(10000*rms_diff[c])) + "_" + bundle_name + ".fib");
+
+        float best_overlap = 0;
+        int best_overlap_index = -1;
+        int m_idx = 0;
+        for (auto ref_mask : reference_masks)
+        {
+          float overlap = fib->GetOverlap(ref_mask, false);
+          if (overlap>best_overlap)
+          {
+            best_overlap = overlap;
+            best_overlap_index = m_idx;
+          }
+          ++m_idx;
+        }
+
+        unsigned int num_voxels = 0;
+        {
+          itk::TractDensityImageFilter< ItkUcharImageType >::Pointer masks_filter = itk::TractDensityImageFilter< ItkUcharImageType >::New();
+          masks_filter->SetInputImage(mask);
+          masks_filter->SetBinaryOutput(true);
+          masks_filter->SetFiberBundle(fib);
+          masks_filter->SetUseImageGeometry(true);
+          masks_filter->Update();
+          num_voxels = masks_filter->GetNumCoveredVoxels();
+        }
+
+        std::cout.rdbuf (old);              // <-- restore
+
+        logfile << "RMS_DIFF: " << setprecision(5) << rms_diff[c] << " " << bundle_name << " " << num_voxels << "\n";
+        if (best_overlap_index>=0)
+          logfile << "Best_overlap: " << setprecision(5) << best_overlap << " " << ist::GetFilenameWithoutExtension(reference_mask_filenames.at(best_overlap_index)) << "\n";
+        else
+          logfile << "No_overlap\n";
+
+        ++c;
+      }
+
+      mitk::FiberBundle::Pointer out_fib = mitk::FiberBundle::New();
+      out_fib = out_fib->AddBundles(input_candidates);
+      out_fib->ColorFibersByFiberWeights(false, true);
+      mitk::IOUtil::Save(out_fib, out_folder + "AllCandidates.fib");
+    }
+    else
+    {
+      MITK_INFO << "RMSE: " << setprecision(5) << rmse;
+      //    fitter->SetPeakImage(peak_image);
+
+      // Iteratively add candidate bundles in a greedy manner
+      while (!input_candidates.empty())
+      {
+        double next_rmse = rmse;
+        double num_peaks = 0;
+        mitk::FiberBundle::Pointer best_candidate = nullptr;
+        PeakImgType::Pointer best_candidate_peak_image = nullptr;
+
+        for (int i=0; i<(int)input_candidates.size(); ++i)
+        {
+          // WHY NECESSARY AGAIN??
+          itk::FitFibersToImageFilter::Pointer fitter = itk::FitFibersToImageFilter::New();
+          fitter->SetLambda(lambda);
+          fitter->SetFilterOutliers(filter_outliers);
+          fitter->SetVerbose(false);
+          fitter->SetPeakImage(peak_image);
+          fitter->SetResampleFibers(false);
+          fitter->SetMaskImage(mask);
+          // ******************************
+          fitter->SetTractograms({input_candidates.at(i)});
+
+          streambuf *old = cout.rdbuf(); // <-- save
+          stringstream ss;
+          std::cout.rdbuf (ss.rdbuf());       // <-- redirect
+          fitter->Update();
+          std::cout.rdbuf (old);              // <-- restore
+
+          double candidate_rmse = fitter->GetRMSE();
+
+          if (candidate_rmse<next_rmse)
+          {
+            next_rmse = candidate_rmse;
+            num_peaks = fitter->GetNumCoveredDirections();
+            best_candidate = fitter->GetTractograms().at(0);
+            best_candidate_peak_image = fitter->GetUnderexplainedImage();
+          }
+        }
+
+        if (best_candidate.IsNull())
+          break;
+
+        //      fitter->SetPeakImage(peak_image);
+        peak_image = best_candidate_peak_image;
+
+        int i=0;
+        std::vector< mitk::FiberBundle::Pointer > remaining_candidates;
+        std::vector< string > remaining_candidate_files;
+        for (auto fib : input_candidates)
+        {
+          if (fib!=best_candidate)
+          {
+            remaining_candidates.push_back(fib);
+            remaining_candidate_files.push_back(candidate_tract_files.at(i));
+          }
+          else
+            name = ist::GetFilenameWithoutExtension(candidate_tract_files.at(i));
+          ++i;
+        }
+        input_candidates = remaining_candidates;
+        candidate_tract_files = remaining_candidate_files;
+
+        iteration++;
+        streambuf *old = cout.rdbuf(); // <-- save
+        stringstream ss;
+        std::cout.rdbuf (ss.rdbuf());       // <-- redirect
+        // Save winning candidate
+        mitk::IOUtil::Save(best_candidate, out_folder + boost::lexical_cast<string>(iteration) + "_" + name + ".fib");
+        peak_image_writer->SetInput(peak_image);
+        peak_image_writer->SetFileName(out_folder + boost::lexical_cast<string>(iteration) + "_" + name + ".nrrd");
+        peak_image_writer->Update();
+
+        // Calculate best overlap with reference masks for evaluation purposes
+        float best_overlap = 0;
+        int best_overlap_index = -1;
+        i = 0;
+        for (auto ref_mask : reference_masks)
+        {
+          float overlap = best_candidate->GetOverlap(ref_mask, false);
+          if (overlap>best_overlap)
+          {
+            best_overlap = overlap;
+            best_overlap_index = i;
+          }
+          ++i;
+        }
+        std::cout.rdbuf (old);              // <-- restore
+
+        logfile << "RMSE: " << setprecision(5) << rmse << " " << name << " " << num_peaks << "\n";
+        if (best_overlap_index>=0)
+          logfile << "Best_overlap: " << setprecision(5) << best_overlap << " " << ist::GetFilenameWithoutExtension(reference_mask_filenames.at(best_overlap_index)) << "\n";
+        else
+          logfile << "No_overlap\n";
+      }
+    }
+
+    clock.Stop();
+    int h = clock.GetTotal()/3600;
+    int m = ((int)clock.GetTotal()%3600)/60;
+    int s = (int)clock.GetTotal()%60;
+    MITK_INFO << "Plausibility estimation took " << h << "h, " << m << "m and " << s << "s";
+    logfile.close();
+  }
+  catch (itk::ExceptionObject e)
+  {
+    std::cout << e;
+    return EXIT_FAILURE;
+  }
+  catch (std::exception e)
+  {
+    std::cout << e.what();
+    return EXIT_FAILURE;
+  }
+  catch (...)
+  {
+    std::cout << "ERROR!?!";
+    return EXIT_FAILURE;
+  }
+  return EXIT_SUCCESS;
+}
diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/CMakeLists.txt b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/CMakeLists.txt
index 9e7cf2c5a7..a72860b7ab 100755
--- a/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/CMakeLists.txt
+++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/CMakeLists.txt
@@ -1,42 +1,44 @@
 option(BUILD_DiffusionTractographyEvaluationCmdApps "Build commandline tools for diffusion fiber tractography evaluation" OFF)
 
 if(BUILD_DiffusionTractographyEvaluationCmdApps OR MITK_BUILD_ALL_APPS)
 
   # needed include directories
   include_directories(
     ${CMAKE_CURRENT_SOURCE_DIR}
     ${CMAKE_CURRENT_BINARY_DIR}
     )
 
     # list of diffusion cmdapps
     # if an app requires additional dependencies
     # they are added after a "^^" and separated by "_"
     set( diffusionTractographyEvaluationcmdapps
     PeaksAngularError^^MitkFiberTracking
     TractometerMetrics^^MitkFiberTracking
-    TractPlausibility^^MitkFiberTracking
-    TractPlausibilityFit^^MitkFiberTracking
+    MergeOverlappingTracts^^MitkFiberTracking
+    ExtractAnchorTracts^^MitkFiberTracking
+    AnchorBasedScoring^^MitkFiberTracking
+    EvaluateLiFE^^MitkFiberTracking
     # LocalDirectionalFiberPlausibility^^MitkFiberTracking # HAS TO USE NEW PEAK IMAGE FORMAT
     )
 
     foreach(diffusionTractographyEvaluationcmdapp ${diffusionTractographyEvaluationcmdapps})
       # extract cmd app name and dependencies
       string(REPLACE "^^" "\\;" cmdapp_info ${diffusionTractographyEvaluationcmdapp})
       set(cmdapp_info_list ${cmdapp_info})
       list(GET cmdapp_info_list 0 appname)
       list(GET cmdapp_info_list 1 raw_dependencies)
       string(REPLACE "_" "\\;" dependencies "${raw_dependencies}")
       set(dependencies_list ${dependencies})
 
       mitkFunctionCreateCommandLineApp(
         NAME ${appname}
         DEPENDS MitkCore MitkDiffusionCore ${dependencies_list}
         PACKAGE_DEPENDS ITK
       )
     endforeach()
 
   if(EXECUTABLE_IS_ENABLED)
     MITK_INSTALL_TARGETS(EXECUTABLES ${EXECUTABLE_TARGET})
   endif()
 
   endif()
diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/EvaluateLiFE.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/EvaluateLiFE.cpp
new file mode 100755
index 0000000000..80e65bf60a
--- /dev/null
+++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/EvaluateLiFE.cpp
@@ -0,0 +1,227 @@
+/*===================================================================
+
+The Medical Imaging Interaction Toolkit (MITK)
+
+Copyright (c) German Cancer Research Center,
+Division of Medical and Biological Informatics.
+All rights reserved.
+
+This software is distributed WITHOUT ANY WARRANTY; without
+even the implied warranty of MERCHANTABILITY or FITNESS FOR
+A PARTICULAR PURPOSE.
+
+See LICENSE.txt or http://www.mitk.org for details.
+
+===================================================================*/
+
+#include <mitkBaseData.h>
+#include <mitkImageCast.h>
+#include <mitkImageToItk.h>
+#include <metaCommand.h>
+#include <mitkCommandLineParser.h>
+#include <usAny.h>
+#include <mitkIOUtil.h>
+#include <boost/lexical_cast.hpp>
+#include <itksys/SystemTools.hxx>
+#include <itkDirectory.h>
+#include <mitkFiberBundle.h>
+#include <vtkTransformPolyDataFilter.h>
+#include <fstream>
+#include <chrono>
+#include <boost/progress.hpp>
+
+using namespace std;
+typedef itksys::SystemTools ist;
+typedef itk::Image<unsigned char, 3>    ItkUcharImgType;
+typedef std::tuple< ItkUcharImgType::Pointer, std::string > MaskType;
+
+ItkUcharImgType::Pointer LoadItkMaskImage(const std::string& filename)
+{
+  mitk::Image::Pointer img = dynamic_cast<mitk::Image*>(mitk::IOUtil::Load(filename)[0].GetPointer());
+  ItkUcharImgType::Pointer itkMask = ItkUcharImgType::New();
+  mitk::CastToItkImage(img, itkMask);
+  return itkMask;
+}
+
+std::vector< MaskType > get_file_list(const std::string& path)
+{
+  std::chrono::milliseconds ms = std::chrono::duration_cast< std::chrono::milliseconds >(std::chrono::system_clock::now().time_since_epoch());
+  std::srand(ms.count());
+
+  std::vector< MaskType > mask_list;
+
+  itk::Directory::Pointer dir = itk::Directory::New();
+
+  if (dir->Load(path.c_str()))
+  {
+    int n = dir->GetNumberOfFiles();
+    int num_images = 0;
+
+    std::vector< int > im_indices;
+    for (int r = 0; r < n; r++)
+    {
+      const char *filename = dir->GetFile(r);
+      std::string ext = ist::GetFilenameExtension(filename);
+      if (ext==".nii" || ext==".nii.gz" || ext==".nrrd")
+      {
+        ++num_images;
+        im_indices.push_back(r);
+      }
+    }
+
+    int c = -1;
+    for (int r : im_indices)
+    {
+      c++;
+      const char *filename = dir->GetFile(r);
+
+      MITK_INFO << "Loading " << ist::GetFilenameWithoutExtension(filename);
+      streambuf *old = cout.rdbuf(); // <-- save
+      stringstream ss;
+      std::cout.rdbuf (ss.rdbuf());       // <-- redirect
+      MaskType m(LoadItkMaskImage(path + '/' + filename), ist::GetFilenameName(filename));
+      mask_list.push_back(m);
+      std::cout.rdbuf (old);              // <-- restore
+    }
+  }
+
+  return mask_list;
+}
+
+/*!
+\brief
+*/
+int main(int argc, char* argv[])
+{
+  mitkCommandLineParser parser;
+
+  parser.setTitle("Evaluate LiFE results");
+  parser.setCategory("Fiber Tracking Evaluation");
+  parser.setDescription("");
+  parser.setContributor("MIC");
+
+  parser.setArgumentPrefix("--", "-");
+  parser.addArgument("input", "i", mitkCommandLineParser::InputFile, "Input:", "input tractogram (.fib, vtk ascii file format)", us::Any(), false);
+  parser.addArgument("out", "o", mitkCommandLineParser::OutputDirectory, "Output:", "output folder", us::Any(), false);
+  parser.addArgument("reference_mask_folder", "m", mitkCommandLineParser::String, "Reference Mask Folder:", "reference masks of known bundles", false);
+  parser.addArgument("overlap", "", mitkCommandLineParser::Float, "Overlap threshold:", "Overlap threshold used to identify true positives", 0.8);
+  parser.addArgument("steps", "", mitkCommandLineParser::Int, "Threshold steps:", "number of weight thresholds used to calculate the ROC curve", 100);
+  parser.addArgument("pre_filter_zeros", "", mitkCommandLineParser::Bool, "Remove zero weights:", "remove fibers with zero weights before starting the evaluation");
+
+  map<string, us::Any> parsedArgs = parser.parseArguments(argc, argv);
+  if (parsedArgs.size()==0)
+    return EXIT_FAILURE;
+
+  string fibFile = us::any_cast<string>(parsedArgs["input"]);
+  string reference_mask_folder = us::any_cast<string>(parsedArgs["reference_mask_folder"]);
+  string out_folder = us::any_cast<string>(parsedArgs["out"]);
+
+  float overlap = 0.8;
+  if (parsedArgs.count("overlap"))
+    overlap = us::any_cast<float>(parsedArgs["overlap"]);
+
+  int steps = 10;
+  if (parsedArgs.count("steps"))
+    steps = us::any_cast<int>(parsedArgs["steps"]);
+
+  bool pre_filter_zeros = false;
+  if (parsedArgs.count("pre_filter_zeros"))
+    pre_filter_zeros = us::any_cast<bool>(parsedArgs["pre_filter_zeros"]);
+
+  try
+  {
+    std::vector< MaskType > known_tract_masks = get_file_list(reference_mask_folder);
+    if (known_tract_masks.empty())
+      return EXIT_FAILURE;
+
+    mitk::FiberBundle::Pointer inputTractogram = dynamic_cast<mitk::FiberBundle*>(mitk::IOUtil::Load(fibFile)[0].GetPointer());
+
+    // resample fibers
+    float minSpacing = 1;
+    if(std::get<0>(known_tract_masks.at(0))->GetSpacing()[0]<std::get<0>(known_tract_masks.at(0))->GetSpacing()[1] && std::get<0>(known_tract_masks.at(0))->GetSpacing()[0]<std::get<0>(known_tract_masks.at(0))->GetSpacing()[2])
+      minSpacing = std::get<0>(known_tract_masks.at(0))->GetSpacing()[0];
+    else if (std::get<0>(known_tract_masks.at(0))->GetSpacing()[1] < std::get<0>(known_tract_masks.at(0))->GetSpacing()[2])
+      minSpacing = std::get<0>(known_tract_masks.at(0))->GetSpacing()[1];
+    else
+      minSpacing = std::get<0>(known_tract_masks.at(0))->GetSpacing()[2];
+    inputTractogram->ResampleLinear(minSpacing/5);
+
+    std::vector< float > weights;
+    for (int i=0; i<inputTractogram->GetNumFibers(); ++i)
+      weights.push_back(inputTractogram->GetFiberWeight(i));
+    std::sort(weights.begin(), weights.end());
+
+    if (pre_filter_zeros)
+      inputTractogram = inputTractogram->FilterByWeights(0.0);
+    mitk::FiberBundle::Pointer pred_positives = inputTractogram->GetDeepCopy();
+    mitk::FiberBundle::Pointer pred_negatives = mitk::FiberBundle::New(nullptr);
+
+    ofstream logfile;
+    logfile.open (out_folder + "LiFE_ROC.txt");
+
+    float fpr = 1.0;
+    float tpr = 1.0;
+    float step = weights.back()/steps;
+    float w = 0;
+    if (!pre_filter_zeros)
+      w -= step;
+    while (pred_positives->GetNumFibers()>0 && fpr>0.001 && tpr>0.001)
+    {
+      w += step;
+
+      streambuf *old = cout.rdbuf(); // <-- save
+      stringstream ss;
+      std::cout.rdbuf (ss.rdbuf());       // <-- redirect
+
+      mitk::FiberBundle::Pointer tp_tracts = mitk::FiberBundle::New(nullptr);
+      mitk::FiberBundle::Pointer fn_tracts = mitk::FiberBundle::New(nullptr);
+      for ( MaskType mask : known_tract_masks )
+      {
+        ItkUcharImgType::Pointer mask_image = std::get<0>(mask);
+
+        mitk::FiberBundle::Pointer a = pred_positives->ExtractFiberSubset(mask_image, true, false, false, overlap, false);
+        tp_tracts = tp_tracts->AddBundle(a);
+
+        mitk::FiberBundle::Pointer b = pred_negatives->ExtractFiberSubset(mask_image, true, false, false, overlap, false);
+        fn_tracts = fn_tracts->AddBundle(b);
+      }
+      mitk::FiberBundle::Pointer fp_tracts = pred_positives->SubtractBundle(tp_tracts);
+      mitk::FiberBundle::Pointer tn_tracts = pred_negatives->SubtractBundle(fn_tracts);
+
+      std::cout.rdbuf (old);              // <-- restore
+
+      float positives = tp_tracts->GetNumFibers() + fn_tracts->GetNumFibers();
+      float negatives = tn_tracts->GetNumFibers() + fp_tracts->GetNumFibers();
+      fpr = (float)fp_tracts->GetNumFibers() / negatives;
+      tpr = (float)tp_tracts->GetNumFibers() / positives;
+
+      float accuracy = 1.0;
+      if (pred_positives->GetNumFibers()>0)
+        accuracy = (float)tp_tracts->GetNumFibers()/pred_positives->GetNumFibers();
+      logfile << w << " " << fpr << " " << tpr << " " << accuracy << " \n";
+      MITK_INFO << "#Fibers: " << pred_positives->GetNumFibers();
+      MITK_INFO << "FPR/TPR: " << fpr << "/" << tpr;
+      MITK_INFO << "Acc: " << accuracy;
+
+      pred_positives = inputTractogram->FilterByWeights(w);
+      pred_negatives = inputTractogram->FilterByWeights(w, true);
+    }
+    logfile.close();
+  }
+  catch (itk::ExceptionObject e)
+  {
+    std::cout << e;
+    return EXIT_FAILURE;
+  }
+  catch (std::exception e)
+  {
+    std::cout << e.what();
+    return EXIT_FAILURE;
+  }
+  catch (...)
+  {
+    std::cout << "ERROR!?!";
+    return EXIT_FAILURE;
+  }
+  return EXIT_SUCCESS;
+}
diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/ExtractAnchorTracts.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/ExtractAnchorTracts.cpp
new file mode 100755
index 0000000000..8479b8344a
--- /dev/null
+++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/ExtractAnchorTracts.cpp
@@ -0,0 +1,269 @@
+/*===================================================================
+
+The Medical Imaging Interaction Toolkit (MITK)
+
+Copyright (c) German Cancer Research Center,
+Division of Medical and Biological Informatics.
+All rights reserved.
+
+This software is distributed WITHOUT ANY WARRANTY; without
+even the implied warranty of MERCHANTABILITY or FITNESS FOR
+A PARTICULAR PURPOSE.
+
+See LICENSE.txt or http://www.mitk.org for details.
+
+===================================================================*/
+
+#include <mitkBaseData.h>
+#include <mitkImageCast.h>
+#include <mitkImageToItk.h>
+#include <metaCommand.h>
+#include <mitkCommandLineParser.h>
+#include <usAny.h>
+#include <mitkIOUtil.h>
+#include <boost/lexical_cast.hpp>
+#include <itksys/SystemTools.hxx>
+#include <itkDirectory.h>
+#include <mitkFiberBundle.h>
+#include <vtkTransformPolyDataFilter.h>
+#include <fstream>
+#include <chrono>
+#include <boost/progress.hpp>
+
+using namespace std;
+typedef itksys::SystemTools ist;
+typedef itk::Image<unsigned char, 3>    ItkUcharImgType;
+typedef std::tuple< ItkUcharImgType::Pointer, std::string > MaskType;
+
+void CreateFolderStructure(const std::string& path)
+{
+  if (ist::PathExists(path))
+    ist::RemoveADirectory(path);
+
+  ist::MakeDirectory(path);
+  ist::MakeDirectory(path + "/anchor_tracts/");
+  ist::MakeDirectory(path + "/candidate_tracts/");
+  ist::MakeDirectory(path + "/implausible_tracts/");
+  ist::MakeDirectory(path + "/skipped_masks/");
+}
+
+ItkUcharImgType::Pointer LoadItkMaskImage(const std::string& filename)
+{
+  mitk::Image::Pointer img = dynamic_cast<mitk::Image*>(mitk::IOUtil::Load(filename)[0].GetPointer());
+  ItkUcharImgType::Pointer itkMask = ItkUcharImgType::New();
+  mitk::CastToItkImage(img, itkMask);
+  return itkMask;
+}
+
+std::vector< MaskType > get_file_list(const std::string& path, float anchor_fraction, const std::string& skipped_path)
+{
+  if (anchor_fraction<0)
+    anchor_fraction = 0;
+  else if (anchor_fraction>1.0)
+    anchor_fraction = 1.0;
+
+  std::chrono::milliseconds ms = std::chrono::duration_cast< std::chrono::milliseconds >(std::chrono::system_clock::now().time_since_epoch());
+  std::srand(ms.count());
+
+  std::vector< MaskType > mask_list;
+
+  itk::Directory::Pointer dir = itk::Directory::New();
+
+  int skipped = 0;
+  if (dir->Load(path.c_str()))
+  {
+    int n = dir->GetNumberOfFiles();
+    int num_images = 0;
+
+    std::vector< int > im_indices;
+    for (int r = 0; r < n; r++)
+    {
+      const char *filename = dir->GetFile(r);
+      std::string ext = ist::GetFilenameExtension(filename);
+      if (ext==".nii" || ext==".nii.gz" || ext==".nrrd")
+      {
+        ++num_images;
+        im_indices.push_back(r);
+      }
+    }
+
+    int skipping_num = num_images * (1.0 - anchor_fraction);
+    std::random_shuffle(im_indices.begin(), im_indices.end());
+    MITK_INFO << "Skipping " << skipping_num << " images";
+    MITK_INFO << "Number of anchors: " << num_images-skipping_num;
+
+    int c = -1;
+    for (int r : im_indices)
+    {
+      c++;
+      const char *filename = dir->GetFile(r);
+
+      if (c<skipping_num && (skipping_num==num_images || ist::GetFilenameWithoutExtension(filename)!="CC"))
+      {
+        MITK_INFO << "Skipping " << ist::GetFilenameWithoutExtension(filename);
+        ist::CopyAFile(path + '/' + filename, skipped_path + ist::GetFilenameName(filename));
+        skipped++;
+        continue;
+      }
+
+      MITK_INFO << "Loading " << ist::GetFilenameWithoutExtension(filename);
+      streambuf *old = cout.rdbuf(); // <-- save
+      stringstream ss;
+      std::cout.rdbuf (ss.rdbuf());       // <-- redirect
+      MaskType m(LoadItkMaskImage(path + '/' + filename), ist::GetFilenameName(filename));
+      mask_list.push_back(m);
+      std::cout.rdbuf (old);              // <-- restore
+    }
+  }
+
+  return mask_list;
+}
+
+mitk::FiberBundle::Pointer TransformToMRtrixSpace(mitk::FiberBundle::Pointer fib)
+{
+  mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New();
+  vtkSmartPointer< vtkMatrix4x4 > matrix = vtkSmartPointer< vtkMatrix4x4 >::New();
+  matrix->Identity();
+  matrix->SetElement(0,0,-matrix->GetElement(0,0));
+  matrix->SetElement(1,1,-matrix->GetElement(1,1));
+  geometry->SetIndexToWorldTransformByVtkMatrix(matrix);
+
+  vtkSmartPointer<vtkTransformPolyDataFilter> transformFilter = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
+  transformFilter->SetInputData(fib->GetFiberPolyData());
+  transformFilter->SetTransform(geometry->GetVtkTransform());
+  transformFilter->Update();
+  mitk::FiberBundle::Pointer transformed_fib = mitk::FiberBundle::New(transformFilter->GetOutput());
+  return transformed_fib;
+}
+
+/*!
+\brief
+*/
+int main(int argc, char* argv[])
+{
+  mitkCommandLineParser parser;
+
+  parser.setTitle("Extract Anchor Tracts");
+  parser.setCategory("Fiber Tracking Evaluation");
+  parser.setDescription("");
+  parser.setContributor("MIC");
+
+  parser.setArgumentPrefix("--", "-");
+  parser.addArgument("input", "i", mitkCommandLineParser::InputFile, "Input:", "input tractogram (.fib, vtk ascii file format)", us::Any(), false);
+  parser.addArgument("out", "o", mitkCommandLineParser::OutputDirectory, "Output:", "output folder", us::Any(), false);
+  parser.addArgument("reference_mask_folder", "m", mitkCommandLineParser::String, "Reference Mask Folder:", "reference masks of known bundles", us::Any(), false);
+  parser.addArgument("gray_matter_mask", "gm", mitkCommandLineParser::String, "GM mask:", "remove fibers not ending in the gray matter");
+  parser.addArgument("anchor_fraction", "", mitkCommandLineParser::Float, "Anchor fraction:", "Fraction of tracts used as anchors", 0.5);
+  parser.addArgument("overlap", "", mitkCommandLineParser::Float, "Overlap threshold:", "Overlap threshold used to identify the anchor tracts", 0.8);
+  parser.addArgument("subsample", "", mitkCommandLineParser::Float, "Subsampling factor:", "Only use specified fraction of input fibers for the analysis", 1.0);
+
+  map<string, us::Any> parsedArgs = parser.parseArguments(argc, argv);
+  if (parsedArgs.size()==0)
+    return EXIT_FAILURE;
+
+  string fibFile = us::any_cast<string>(parsedArgs["input"]);
+  string reference_mask_folder = us::any_cast<string>(parsedArgs["reference_mask_folder"]);
+  string out_folder = us::any_cast<string>(parsedArgs["out"]);
+
+  string gray_matter_mask = "";
+  if (parsedArgs.count("gray_matter_mask"))
+    gray_matter_mask = us::any_cast<string>(parsedArgs["gray_matter_mask"]);
+
+  float anchor_fraction = 0.5;
+  if (parsedArgs.count("anchor_fraction"))
+    anchor_fraction = us::any_cast<float>(parsedArgs["anchor_fraction"]);
+
+  float overlap = 0.8;
+  if (parsedArgs.count("overlap"))
+    overlap = us::any_cast<float>(parsedArgs["overlap"]);
+
+  float subsample = 1.0;
+  if (parsedArgs.count("subsample"))
+    subsample = us::any_cast<float>(parsedArgs["subsample"]);
+
+  try
+  {
+    CreateFolderStructure(out_folder);
+    std::vector< MaskType > known_tract_masks = get_file_list(reference_mask_folder, anchor_fraction, out_folder + "/skipped_masks/");
+    mitk::FiberBundle::Pointer inputTractogram = dynamic_cast<mitk::FiberBundle*>(mitk::IOUtil::Load(fibFile)[0].GetPointer());
+
+    MITK_INFO << "Removing fibers not ending inside of GM";
+    if (gray_matter_mask.compare("")!=0)
+    {
+      streambuf *old = cout.rdbuf(); // <-- save
+      stringstream ss;
+      std::cout.rdbuf (ss.rdbuf());       // <-- redirect
+      ItkUcharImgType::Pointer gm_image = LoadItkMaskImage(gray_matter_mask);
+      std::cout.rdbuf (old);              // <-- restore
+
+      mitk::FiberBundle::Pointer not_gm_fibers = inputTractogram->ExtractFiberSubset(gm_image, false, true, true);
+
+      old = cout.rdbuf(); // <-- save
+      std::cout.rdbuf (ss.rdbuf());       // <-- redirect
+      mitk::IOUtil::Save(not_gm_fibers, out_folder + "/implausible_tracts/no_gm_endings.trk");
+      inputTractogram = inputTractogram->ExtractFiberSubset(gm_image, false, false, true);
+      std::cout.rdbuf (old);              // <-- restore
+    }
+
+    if (subsample<1.0)
+      inputTractogram = inputTractogram->SubsampleFibers(subsample);
+
+
+    // resample fibers
+    float minSpacing = 1;
+    if (!known_tract_masks.empty())
+    {
+      if(std::get<0>(known_tract_masks.at(0))->GetSpacing()[0]<std::get<0>(known_tract_masks.at(0))->GetSpacing()[1] && std::get<0>(known_tract_masks.at(0))->GetSpacing()[0]<std::get<0>(known_tract_masks.at(0))->GetSpacing()[2])
+        minSpacing = std::get<0>(known_tract_masks.at(0))->GetSpacing()[0];
+      else if (std::get<0>(known_tract_masks.at(0))->GetSpacing()[1] < std::get<0>(known_tract_masks.at(0))->GetSpacing()[2])
+        minSpacing = std::get<0>(known_tract_masks.at(0))->GetSpacing()[1];
+      else
+        minSpacing = std::get<0>(known_tract_masks.at(0))->GetSpacing()[2];
+    }
+    inputTractogram->ResampleLinear(minSpacing/5);
+
+    mitk::FiberBundle::Pointer all_anchor_tracts = mitk::FiberBundle::New(nullptr);
+    if (!known_tract_masks.empty())
+    {
+      MITK_INFO << "Find known tracts via overlap match";
+      boost::progress_display disp(known_tract_masks.size());
+      for ( MaskType mask : known_tract_masks )
+      {
+        ++disp;
+        streambuf *old = cout.rdbuf(); // <-- save
+        stringstream ss;
+        std::cout.rdbuf (ss.rdbuf());       // <-- redirect
+
+        ItkUcharImgType::Pointer mask_image = std::get<0>(mask);
+        std::string mask_name = std::get<1>(mask);
+        mitk::FiberBundle::Pointer known_tract = inputTractogram->ExtractFiberSubset(mask_image, true, false, false, overlap, false);
+        mitk::IOUtil::Save(known_tract, out_folder + "/anchor_tracts/" + mask_name + ".trk");
+
+        all_anchor_tracts = all_anchor_tracts->AddBundle(known_tract);
+
+        std::cout.rdbuf (old);              // <-- restore
+      }
+    }
+
+    mitk::IOUtil::Save(all_anchor_tracts, out_folder + "/anchor_tracts/anchor_tractogram.trk");
+    mitk::FiberBundle::Pointer remaining_tracts = inputTractogram->SubtractBundle(all_anchor_tracts);
+    mitk::IOUtil::Save(remaining_tracts, out_folder + "/candidate_tracts/candidate_tractogram.trk");
+    mitk::IOUtil::Save(inputTractogram, out_folder + "/filtered_tractogram.trk");
+  }
+  catch (itk::ExceptionObject e)
+  {
+    std::cout << e;
+    return EXIT_FAILURE;
+  }
+  catch (std::exception e)
+  {
+    std::cout << e.what();
+    return EXIT_FAILURE;
+  }
+  catch (...)
+  {
+    std::cout << "ERROR!?!";
+    return EXIT_FAILURE;
+  }
+  return EXIT_SUCCESS;
+}
diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/MergeOverlappingTracts.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/MergeOverlappingTracts.cpp
new file mode 100755
index 0000000000..673202ff03
--- /dev/null
+++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/MergeOverlappingTracts.cpp
@@ -0,0 +1,252 @@
+/*===================================================================
+
+The Medical Imaging Interaction Toolkit (MITK)
+
+Copyright (c) German Cancer Research Center,
+Division of Medical and Biological Informatics.
+All rights reserved.
+
+This software is distributed WITHOUT ANY WARRANTY; without
+even the implied warranty of MERCHANTABILITY or FITNESS FOR
+A PARTICULAR PURPOSE.
+
+See LICENSE.txt or http://www.mitk.org for details.
+
+===================================================================*/
+
+#include <mitkBaseData.h>
+#include <mitkImageCast.h>
+#include <mitkImageToItk.h>
+#include <metaCommand.h>
+#include <mitkCommandLineParser.h>
+#include <usAny.h>
+#include <mitkIOUtil.h>
+#include <boost/lexical_cast.hpp>
+#include <itksys/SystemTools.hxx>
+#include <itkDirectory.h>
+#include <mitkFiberBundle.h>
+#include <vtkTransformPolyDataFilter.h>
+#include <fstream>
+#include <chrono>
+#include <boost/progress.hpp>
+#include <itkTractsToFiberEndingsImageFilter.h>
+#include <itkTractDensityImageFilter.h>
+#include <itkImageRegionConstIterator.h>
+#include <itkImageFileWriter.h>
+
+using namespace std;
+typedef itksys::SystemTools ist;
+typedef itk::Image<unsigned char, 3>    ItkUcharImgType;
+typedef itk::Image<unsigned int, 3>    ItkUIntImgType;
+
+std::vector< string > get_file_list(const std::string& path, std::vector< string > extensions={".fib", ".trk"})
+{
+  std::vector< string > file_list;
+  itk::Directory::Pointer dir = itk::Directory::New();
+
+  if (dir->Load(path.c_str()))
+  {
+    int n = dir->GetNumberOfFiles();
+    for (int r = 0; r < n; r++)
+    {
+      const char *filename = dir->GetFile(r);
+      std::string ext = ist::GetFilenameExtension(filename);
+      for (auto e : extensions)
+      {
+        if (ext==e)
+        {
+          file_list.push_back(path + '/' + filename);
+          break;
+        }
+      }
+    }
+  }
+  return file_list;
+}
+
+/*!
+\brief
+*/
+int main(int argc, char* argv[])
+{
+  mitkCommandLineParser parser;
+
+  parser.setTitle("Merge Overlapping Tracts");
+  parser.setCategory("Fiber Tracking Evaluation");
+  parser.setDescription("");
+  parser.setContributor("MIC");
+
+  parser.setArgumentPrefix("--", "-");
+  parser.addArgument("in", "i", mitkCommandLineParser::InputFile, "Input Folder:", "input folder", us::Any(), false);
+  parser.addArgument("out", "o", mitkCommandLineParser::OutputDirectory, "Output Folder:", "output folder", us::Any(), false);
+  parser.addArgument("overlap", "", mitkCommandLineParser::Float, "Overlap threshold:", "Tracts with overlap larger than this threshold are merged", false, 0.8);
+
+  map<string, us::Any> parsedArgs = parser.parseArguments(argc, argv);
+  if (parsedArgs.size()==0)
+    return EXIT_FAILURE;
+
+  string input_folder = us::any_cast<string>(parsedArgs["in"]);
+  string out_folder = us::any_cast<string>(parsedArgs["out"]);
+
+  float overlap = 0.8;
+  if (parsedArgs.count("overlap"))
+    overlap = us::any_cast<float>(parsedArgs["overlap"]);
+
+  try
+  {
+    if (ist::PathExists(out_folder))
+      ist::RemoveADirectory(out_folder);
+    ist::MakeDirectory(out_folder);
+
+    std::vector< string > fib_files = get_file_list(input_folder, {".fib", ".trk", ".tck"});
+    if (fib_files.empty())
+      return EXIT_FAILURE;
+
+    streambuf *old = cout.rdbuf(); // <-- save
+    stringstream ss;
+    std::cout.rdbuf (ss.rdbuf());       // <-- redirect
+
+    std::vector< mitk::FiberBundle::Pointer > fibs;
+    for (string f : fib_files)
+    {
+      mitk::FiberBundle::Pointer fib = dynamic_cast<mitk::FiberBundle*>(mitk::IOUtil::Load(f)[0].GetPointer());
+      fibs.push_back(fib);
+    }
+
+    mitk::FiberBundle::Pointer combined = mitk::FiberBundle::New();
+    combined = combined->AddBundles(fibs);
+
+    itk::TractsToFiberEndingsImageFilter< ItkUcharImgType >::Pointer endings = itk::TractsToFiberEndingsImageFilter< ItkUcharImgType >::New();
+    endings->SetFiberBundle(combined);
+    endings->SetUpsamplingFactor(0.25);
+    endings->Update();
+    ItkUcharImgType::Pointer ref_image = endings->GetOutput();
+
+    std::cout.rdbuf (old);              // <-- restore
+
+    for (int its = 0; its<3; its++)
+    {
+      streambuf *old = cout.rdbuf(); // <-- save
+      stringstream ss;
+      std::cout.rdbuf (ss.rdbuf());       // <-- redirect
+
+      std::vector< ItkUcharImgType::Pointer > mask_images;
+      for (auto fib : fibs)
+      {
+        itk::TractDensityImageFilter< ItkUcharImgType >::Pointer masks = itk::TractDensityImageFilter< ItkUcharImgType >::New();
+        masks->SetInputImage(ref_image);
+        masks->SetBinaryOutput(true);
+        masks->SetFiberBundle(fib);
+        masks->SetUseImageGeometry(true);
+        masks->Update();
+        mask_images.push_back(masks->GetOutput());
+      }
+
+      int r=0;
+      vnl_matrix< int > mat; mat.set_size(mask_images.size(), mask_images.size()); mat.fill(0);
+      for (auto m1 : mask_images)
+      {
+        float max_overlap = overlap;
+        int c = 0;
+        for (auto m2 : mask_images)
+        {
+          if (c<=r)
+          {
+            ++c;
+            continue;
+          }
+
+          itk::ImageRegionConstIterator<ItkUcharImgType> it1(m1, m1->GetLargestPossibleRegion());
+          itk::ImageRegionConstIterator<ItkUcharImgType> it2(m2, m2->GetLargestPossibleRegion());
+
+          unsigned int c1 = 0;
+          unsigned int c2 = 0;
+          unsigned int intersect = 0;
+          while( !it1.IsAtEnd() )
+          {
+            if( it1.Get()>0 && it2.Get()>0)
+              ++intersect;
+            if(it1.Get()>0)
+              ++c1;
+            if(it2.Get()>0)
+              ++c2;
+            ++it1;
+            ++it2;
+          }
+
+          if ( (float)intersect/c1>max_overlap )
+          {
+            max_overlap = (float)intersect/c1;
+            mat.put(r,c, 1);
+          }
+          if ( (float)intersect/c2>max_overlap )
+          {
+            max_overlap = (float)intersect/c2;
+            mat.put(r,c, 1);
+          }
+          ++c;
+        }
+
+        ++r;
+      }
+
+      std::vector< mitk::FiberBundle::Pointer > out_fibs;
+      std::vector< bool > used;
+      for (unsigned int i=0; i<fibs.size(); i++)
+        used.push_back(false);
+      for (unsigned int r=0; r<mask_images.size(); r++)
+      {
+        if (used.at(r))
+          continue;
+
+        mitk::FiberBundle::Pointer fib = fibs.at(r);
+        for (unsigned int c=r+1; c<mask_images.size(); c++)
+        {
+          if (mat.get(r,c)>0)
+          {
+            fib = fib->AddBundle(fibs.at(c));
+            MITK_INFO << c;
+            used[c] = true;
+          }
+        }
+
+        out_fibs.push_back(fib);
+      }
+      std::cout.rdbuf (old);              // <-- restore
+
+      MITK_INFO << fibs.size() << " --> " << out_fibs.size();
+
+      if (fibs.size()==out_fibs.size())
+        break;
+      fibs = out_fibs;
+    }
+
+    int c = 0;
+    for (auto fib : fibs)
+    {
+      streambuf *old = cout.rdbuf(); // <-- save
+      stringstream ss;
+      std::cout.rdbuf (ss.rdbuf());       // <-- redirect
+      mitk::IOUtil::Save(fib, out_folder + "/bundle_" + boost::lexical_cast<string>(c) + ".trk");
+      std::cout.rdbuf (old);              // <-- restore
+
+      ++c;
+    }
+  }
+  catch (itk::ExceptionObject e)
+  {
+    std::cout << e;
+    return EXIT_FAILURE;
+  }
+  catch (std::exception e)
+  {
+    std::cout << e.what();
+    return EXIT_FAILURE;
+  }
+  catch (...)
+  {
+    std::cout << "ERROR!?!";
+    return EXIT_FAILURE;
+  }
+  return EXIT_SUCCESS;
+}
diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/TractPlausibility.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/TractPlausibility.cpp
deleted file mode 100755
index ecf520ae8f..0000000000
--- a/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/TractPlausibility.cpp
+++ /dev/null
@@ -1,208 +0,0 @@
-/*===================================================================
-
-The Medical Imaging Interaction Toolkit (MITK)
-
-Copyright (c) German Cancer Research Center,
-Division of Medical and Biological Informatics.
-All rights reserved.
-
-This software is distributed WITHOUT ANY WARRANTY; without
-even the implied warranty of MERCHANTABILITY or FITNESS FOR
-A PARTICULAR PURPOSE.
-
-See LICENSE.txt or http://www.mitk.org for details.
-
-===================================================================*/
-
-#include <mitkBaseData.h>
-#include <mitkImageCast.h>
-#include <mitkImageToItk.h>
-#include <metaCommand.h>
-#include <mitkCommandLineParser.h>
-#include <usAny.h>
-#include <mitkIOUtil.h>
-#include <boost/lexical_cast.hpp>
-#include <itksys/SystemTools.hxx>
-#include <itkDirectory.h>
-#include <mitkFiberBundle.h>
-#include <vtkTransformPolyDataFilter.h>
-#include <fstream>
-
-using namespace std;
-typedef itksys::SystemTools ist;
-typedef itk::Image<unsigned char, 3>    ItkUcharImgType;
-typedef std::tuple< ItkUcharImgType::Pointer, std::string > MaskType;
-
-void CreateFolderStructure(const std::string& path)
-{
-  if (ist::PathExists(path))
-    ist::RemoveADirectory(path);
-
-  ist::MakeDirectory(path);
-  ist::MakeDirectory(path + "/known_tracts/");
-  ist::MakeDirectory(path + "/plausible_tracts/");
-  ist::MakeDirectory(path + "/implausible_tracts/");
-}
-
-ItkUcharImgType::Pointer LoadItkMaskImage(const std::string& filename)
-{
-  mitk::Image::Pointer img = dynamic_cast<mitk::Image*>(mitk::IOUtil::Load(filename)[0].GetPointer());
-  ItkUcharImgType::Pointer itkMask = ItkUcharImgType::New();
-  mitk::CastToItkImage(img, itkMask);
-  return itkMask;
-}
-
-std::vector< MaskType > get_file_list(const std::string& path, const std::string& skipped)
-{
-  std::srand(std::time(0));
-
-  std::vector< MaskType > mask_list;
-
-  itk::Directory::Pointer dir = itk::Directory::New();
-
-  ofstream myfile;
-  myfile.open (skipped);
-  if (dir->Load(path.c_str()))
-  {
-    int n = dir->GetNumberOfFiles();
-    for (int r = 0; r < n; r++)
-    {
-      const char *filename = dir->GetFile(r);
-
-      if (std::rand()%3==0 && ist::GetFilenameWithoutExtension(filename)!="CC")
-      {
-        MITK_INFO << "Dismissing " << ist::GetFilenameWithoutExtension(filename);
-        myfile << ist::GetFilenameName(filename) << "\n";
-        continue;
-      }
-
-      std::string ext = ist::GetFilenameExtension(filename);
-      if (ext==".nii" || ext==".nii.gz" || ext==".nrrd")
-      {
-        MITK_INFO << "Loading " << ist::GetFilenameWithoutExtension(filename);
-        streambuf *old = cout.rdbuf(); // <-- save
-        stringstream ss;
-        std::cout.rdbuf (ss.rdbuf());       // <-- redirect
-
-        MaskType m(LoadItkMaskImage(path + '/' + filename), ist::GetFilenameWithoutExtension(filename));
-        mask_list.push_back(m);
-
-        std::cout.rdbuf (old);              // <-- restore
-      }
-    }
-  }
-  myfile.close();
-
-  return mask_list;
-}
-
-mitk::FiberBundle::Pointer TransformToMRtrixSpace(mitk::FiberBundle::Pointer fib)
-{
-  mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New();
-  vtkSmartPointer< vtkMatrix4x4 > matrix = vtkSmartPointer< vtkMatrix4x4 >::New();
-  matrix->Identity();
-  matrix->SetElement(0,0,-matrix->GetElement(0,0));
-  matrix->SetElement(1,1,-matrix->GetElement(1,1));
-  geometry->SetIndexToWorldTransformByVtkMatrix(matrix);
-
-  vtkSmartPointer<vtkTransformPolyDataFilter> transformFilter = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
-  transformFilter->SetInputData(fib->GetFiberPolyData());
-  transformFilter->SetTransform(geometry->GetVtkTransform());
-  transformFilter->Update();
-  mitk::FiberBundle::Pointer transformed_fib = mitk::FiberBundle::New(transformFilter->GetOutput());
-  return transformed_fib;
-}
-
-/*!
-\brief
-*/
-int main(int argc, char* argv[])
-{
-  mitkCommandLineParser parser;
-
-  parser.setTitle("Tract Plausibility");
-  parser.setCategory("Fiber Tracking Evaluation");
-  parser.setDescription("");
-  parser.setContributor("MIC");
-
-  parser.setArgumentPrefix("--", "-");
-  parser.addArgument("input", "i", mitkCommandLineParser::InputFile, "Input:", "input tractogram (.fib, vtk ascii file format)", us::Any(), false);
-  parser.addArgument("out", "o", mitkCommandLineParser::OutputDirectory, "Output:", "output folder", us::Any(), false);
-  parser.addArgument("reference_mask_folder", "m", mitkCommandLineParser::String, "Reference Mask Folder:", "reference masks of known bundles", false);
-  parser.addArgument("gray_matter_mask", "gm", mitkCommandLineParser::String, "", "", false);
-
-  map<string, us::Any> parsedArgs = parser.parseArguments(argc, argv);
-  if (parsedArgs.size()==0)
-    return EXIT_FAILURE;
-
-  string fibFile = us::any_cast<string>(parsedArgs["input"]);
-  string gray_matter_mask = us::any_cast<string>(parsedArgs["gray_matter_mask"]);
-  string reference_mask_folder = us::any_cast<string>(parsedArgs["reference_mask_folder"]);
-  string out_folder = us::any_cast<string>(parsedArgs["out"]);
-
-  try
-  {
-    CreateFolderStructure(out_folder);
-
-    std::vector< MaskType > known_tract_masks = get_file_list(reference_mask_folder, out_folder + "skipped_masks.txt");
-    if (known_tract_masks.empty())
-      return EXIT_FAILURE;
-
-    ItkUcharImgType::Pointer gm_image = LoadItkMaskImage(gray_matter_mask);
-
-    mitk::FiberBundle::Pointer inputTractogram = dynamic_cast<mitk::FiberBundle*>(mitk::IOUtil::Load(fibFile)[0].GetPointer());
-
-    // filter gray matter fibers
-    mitk::FiberBundle::Pointer not_gm_fibers = inputTractogram->ExtractFiberSubset(gm_image, false, true, true);
-    mitk::IOUtil::Save(not_gm_fibers, out_folder + "/implausible_tracts/no_gm_endings.trk");
-    inputTractogram = inputTractogram->ExtractFiberSubset(gm_image, false, false, true);
-
-    // resample fibers
-    float minSpacing = 1;
-    if(std::get<0>(known_tract_masks.at(0))->GetSpacing()[0]<std::get<0>(known_tract_masks.at(0))->GetSpacing()[1] && std::get<0>(known_tract_masks.at(0))->GetSpacing()[0]<std::get<0>(known_tract_masks.at(0))->GetSpacing()[2])
-      minSpacing = std::get<0>(known_tract_masks.at(0))->GetSpacing()[0];
-    else if (std::get<0>(known_tract_masks.at(0))->GetSpacing()[1] < std::get<0>(known_tract_masks.at(0))->GetSpacing()[2])
-      minSpacing = std::get<0>(known_tract_masks.at(0))->GetSpacing()[1];
-    else
-      minSpacing = std::get<0>(known_tract_masks.at(0))->GetSpacing()[2];
-    inputTractogram->ResampleLinear(minSpacing/5);
-
-    // find known tracts via overlap match
-    mitk::FiberBundle::Pointer all_known_tracts = nullptr;
-    for ( MaskType mask : known_tract_masks )
-    {
-      ItkUcharImgType::Pointer mask_image = std::get<0>(mask);
-      std::string mask_name = std::get<1>(mask);
-      mitk::FiberBundle::Pointer known_tract = inputTractogram->ExtractFiberSubset(mask_image, true, false, false, 0.7, false);
-      mitk::IOUtil::Save(known_tract, out_folder + "/known_tracts/" + mask_name + ".trk");
-
-      if (all_known_tracts.IsNull())
-        all_known_tracts = mitk::FiberBundle::New(known_tract->GetFiberPolyData());
-      else
-        all_known_tracts = all_known_tracts->AddBundle(known_tract);
-    }
-    mitk::IOUtil::Save(all_known_tracts, out_folder + "/known_tracts/all_known_tracts.trk");
-    mitk::IOUtil::Save(TransformToMRtrixSpace(all_known_tracts), out_folder + "/known_tracts/all_known_tracts_mrtrixspace.fib");
-
-    mitk::FiberBundle::Pointer remaining_tracts = inputTractogram->SubtractBundle(all_known_tracts);
-    mitk::IOUtil::Save(remaining_tracts, out_folder + "/plausible_tracts/remaining_tracts.trk");
-    mitk::IOUtil::Save(TransformToMRtrixSpace(remaining_tracts), out_folder + "/plausible_tracts/remaining_tracts_mrtrixspace.fib");
-    MITK_INFO << "step_size: " << minSpacing/5;
-  }
-  catch (itk::ExceptionObject e)
-  {
-    std::cout << e;
-    return EXIT_FAILURE;
-  }
-  catch (std::exception e)
-  {
-    std::cout << e.what();
-    return EXIT_FAILURE;
-  }
-  catch (...)
-  {
-    std::cout << "ERROR!?!";
-    return EXIT_FAILURE;
-  }
-  return EXIT_SUCCESS;
-}
diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/TractPlausibilityFit.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/TractPlausibilityFit.cpp
deleted file mode 100755
index 6b1f1240c0..0000000000
--- a/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/TractPlausibilityFit.cpp
+++ /dev/null
@@ -1,292 +0,0 @@
-/*===================================================================
-
-The Medical Imaging Interaction Toolkit (MITK)
-
-Copyright (c) German Cancer Research Center,
-Division of Medical and Biological Informatics.
-All rights reserved.
-
-This software is distributed WITHOUT ANY WARRANTY; without
-even the implied warranty of MERCHANTABILITY or FITNESS FOR
-A PARTICULAR PURPOSE.
-
-See LICENSE.txt or http://www.mitk.org for details.
-
-===================================================================*/
-
-#include <mitkBaseData.h>
-#include <mitkImageCast.h>
-#include <mitkImageToItk.h>
-#include <metaCommand.h>
-#include <mitkCommandLineParser.h>
-#include <usAny.h>
-#include <mitkIOUtil.h>
-#include <itksys/SystemTools.hxx>
-#include <itkDirectory.h>
-#include <mitkFiberBundle.h>
-#include <mitkPreferenceListReaderOptionsFunctor.h>
-#include <itkImageFileWriter.h>
-#include <mitkPeakImage.h>
-#include <itkFitFibersToImageFilter.h>
-#include <boost/lexical_cast.hpp>
-
-using namespace std;
-typedef itksys::SystemTools ist;
-typedef itk::Point<float, 4> PointType4;
-typedef itk::Image< float, 4 >  PeakImgType;
-
-std::vector< string > get_file_list(const std::string& path)
-{
-  std::vector< string > file_list;
-  itk::Directory::Pointer dir = itk::Directory::New();
-
-  if (dir->Load(path.c_str()))
-  {
-    int n = dir->GetNumberOfFiles();
-    for (int r = 0; r < n; r++)
-    {
-      const char *filename = dir->GetFile(r);
-      std::string ext = ist::GetFilenameExtension(filename);
-      if (ext==".fib" || ext==".trk")
-        file_list.push_back(path + '/' + filename);
-    }
-  }
-  return file_list;
-}
-
-/*!
-\brief Fits the tractogram to the input peak image by assigning a weight to each fiber (similar to https://doi.org/10.1016/j.neuroimage.2015.06.092).
-*/
-int main(int argc, char* argv[])
-{
-  mitkCommandLineParser parser;
-
-  parser.setTitle("");
-  parser.setCategory("Fiber Tracking Evaluation");
-  parser.setDescription("");
-  parser.setContributor("MIC");
-
-  parser.setArgumentPrefix("--", "-");
-  parser.addArgument("", "i1", mitkCommandLineParser::InputFile, "Input tractogram:", "input tractogram (.fib, vtk ascii file format)", us::Any(), false);
-  parser.addArgument("", "i2", mitkCommandLineParser::InputFile, "Input peaks:", "input peak image", us::Any(), false);
-  parser.addArgument("", "i3", mitkCommandLineParser::InputFile, "", "", us::Any(), false);
-  parser.addArgument("", "o", mitkCommandLineParser::OutputDirectory, "Output:", "output root", us::Any());
-
-  parser.addArgument("mask", "", mitkCommandLineParser::InputFile, "", "", us::Any(), false);
-  parser.addArgument("min_gain", "", mitkCommandLineParser::Float, "Min. gain:", "process stops if remaining bundles don't contribute enough", 0.05);
-
-
-  parser.addArgument("max_iter", "", mitkCommandLineParser::Int, "Max. iterations:", "maximum number of optimizer iterations", 20);
-  parser.addArgument("bundle_based", "", mitkCommandLineParser::Bool, "Bundle based fit:", "fit one weight per input tractogram/bundle, not for each fiber", false);
-  parser.addArgument("min_g", "", mitkCommandLineParser::Float, "Min. gradient:", "lower termination threshold for gradient magnitude", 1e-5);
-  parser.addArgument("lambda", "", mitkCommandLineParser::Float, "Lambda:", "modifier for regularization", 0.1);
-  parser.addArgument("dont_filter_outliers", "", mitkCommandLineParser::Bool, "Don't filter outliers:", "don't perform second optimization run with an upper weight bound based on the first weight estimation (95% quantile)", false);
-
-  map<string, us::Any> parsedArgs = parser.parseArguments(argc, argv);
-  if (parsedArgs.size()==0)
-    return EXIT_FAILURE;
-
-  string fib_file = us::any_cast<string>(parsedArgs["i1"]);
-  string peak_file_name = us::any_cast<string>(parsedArgs["i2"]);
-  string candidate_folder = us::any_cast<string>(parsedArgs["i3"]);
-  string outRoot = us::any_cast<string>(parsedArgs["o"]);
-
-  bool single_fib = true;
-  if (parsedArgs.count("bundle_based"))
-    single_fib = !us::any_cast<bool>(parsedArgs["bundle_based"]);
-
-  int max_iter = 20;
-  if (parsedArgs.count("max_iter"))
-    max_iter = us::any_cast<int>(parsedArgs["max_iter"]);
-
-  float g_tol = 1e-5;
-  if (parsedArgs.count("min_g"))
-    g_tol = us::any_cast<float>(parsedArgs["min_g"]);
-
-  float min_gain = 0.05;
-  if (parsedArgs.count("min_gain"))
-    min_gain = us::any_cast<float>(parsedArgs["min_gain"]);
-
-  float lambda = 0.1;
-  if (parsedArgs.count("lambda"))
-    lambda = us::any_cast<float>(parsedArgs["lambda"]);
-
-  bool filter_outliers = true;
-  if (parsedArgs.count("dont_filter_outliers"))
-    filter_outliers = !us::any_cast<bool>(parsedArgs["dont_filter_outliers"]);
-
-  string mask_file = "";
-  if (parsedArgs.count("mask"))
-    mask_file = us::any_cast<string>(parsedArgs["mask"]);
-
-  try
-  {
-    itk::TimeProbe clock;
-    clock.Start();
-
-    mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor({"Peak Image", "Fiberbundles"}, {});
-    mitk::Image::Pointer inputImage = dynamic_cast<mitk::PeakImage*>(mitk::IOUtil::Load(peak_file_name, &functor)[0].GetPointer());
-
-    itk::FitFibersToImageFilter::UcharImgType::Pointer mask = nullptr;
-    if (mask_file.compare("")!=0)
-    {
-      mitk::Image::Pointer mitk_mask = dynamic_cast<mitk::Image*>(mitk::IOUtil::Load(mask_file)[0].GetPointer());
-      mitk::CastToItkImage(mitk_mask, mask);
-    }
-
-    typedef mitk::ImageToItk< PeakImgType > CasterType;
-    CasterType::Pointer caster = CasterType::New();
-    caster->SetInput(inputImage);
-    caster->Update();
-    PeakImgType::Pointer peak_image = caster->GetOutput();
-
-    std::vector< mitk::FiberBundle::Pointer > input_reference;
-    mitk::FiberBundle::Pointer fib = dynamic_cast<mitk::FiberBundle*>(mitk::IOUtil::Load(fib_file)[0].GetPointer());
-    if (fib.IsNull())
-      return EXIT_FAILURE;
-    input_reference.push_back(fib);
-
-    std::vector< mitk::FiberBundle::Pointer > input_candidates;
-    std::vector< string > candidate_tract_files = get_file_list(candidate_folder);
-    for (string f : candidate_tract_files)
-    {
-      mitk::FiberBundle::Pointer fib = dynamic_cast<mitk::FiberBundle*>(mitk::IOUtil::Load(f)[0].GetPointer());
-      if (fib.IsNull())
-        continue;
-      input_candidates.push_back(fib);
-    }
-
-    int iteration = 0;
-    std::string name = ist::GetFilenameWithoutExtension(fib_file);
-
-    itk::FitFibersToImageFilter::Pointer fitter = itk::FitFibersToImageFilter::New();
-    fitter->SetTractograms(input_reference);
-    fitter->SetFitIndividualFibers(single_fib);
-    fitter->SetMaxIterations(max_iter);
-    fitter->SetGradientTolerance(g_tol);
-    fitter->SetLambda(lambda);
-    fitter->SetFilterOutliers(filter_outliers);
-    fitter->SetPeakImage(peak_image);
-    fitter->SetVerbose(true);
-    fitter->SetDeepCopy(false);
-    fitter->SetMaskImage(mask);
-    fitter->Update();
-
-//    fitter->GetTractograms().at(0)->SetFiberWeights(fitter->GetCoverage());
-//    fitter->GetTractograms().at(0)->ColorFibersByFiberWeights(false, false);
-
-    mitk::IOUtil::Save(fitter->GetTractograms().at(0), outRoot + "0_" + name + ".fib");
-    peak_image = fitter->GetUnderexplainedImage();
-
-    itk::ImageFileWriter< PeakImgType >::Pointer writer = itk::ImageFileWriter< PeakImgType >::New();
-    writer->SetInput(peak_image);
-    writer->SetFileName(outRoot + boost::lexical_cast<string>(iteration) + "_" + name + ".nrrd");
-    writer->Update();
-
-    double coverage = fitter->GetCoverage();
-    MITK_INFO << "Iteration: " << iteration;
-    MITK_INFO << std::fixed << "Coverage: " << setprecision(2) << 100.0*coverage << "%";
-//    fitter->SetPeakImage(peak_image);
-
-    while (!input_candidates.empty())
-    {
-      streambuf *old = cout.rdbuf(); // <-- save
-      stringstream ss;
-      std::cout.rdbuf (ss.rdbuf());       // <-- redirect
-
-      double next_coverage = 0;
-      mitk::FiberBundle::Pointer best_candidate = nullptr;
-      for (auto fib : input_candidates)
-      {
-
-        // WHY NECESSARY AGAIN??
-        itk::FitFibersToImageFilter::Pointer fitter = itk::FitFibersToImageFilter::New();
-        fitter->SetFitIndividualFibers(single_fib);
-        fitter->SetMaxIterations(max_iter);
-        fitter->SetGradientTolerance(g_tol);
-        fitter->SetLambda(lambda);
-        fitter->SetFilterOutliers(filter_outliers);
-        fitter->SetVerbose(false);
-        fitter->SetPeakImage(peak_image);
-        fitter->SetDeepCopy(false);
-        fitter->SetMaskImage(mask);
-        // ******************************
-        fitter->SetTractograms({fib});
-        fitter->Update();
-
-        double candidate_coverage = fitter->GetCoverage();
-
-        if (candidate_coverage>next_coverage)
-        {
-          next_coverage = candidate_coverage;
-          if ((1.0-coverage) * next_coverage >= min_gain)
-          {
-            best_candidate = fitter->GetTractograms().at(0);
-            peak_image = fitter->GetUnderexplainedImage();
-          }
-        }
-      }
-
-      if (best_candidate.IsNull())
-      {
-        std::cout.rdbuf (old);              // <-- restore
-        break;
-      }
-
-//      fitter->SetPeakImage(peak_image);
-//      best_candidate->SetFiberWeights((1.0-coverage) * next_coverage);
-//      best_candidate->ColorFibersByFiberWeights(false, false);
-
-      coverage += (1.0-coverage) * next_coverage;
-
-      int i=0;
-      std::vector< mitk::FiberBundle::Pointer > remaining_candidates;
-      std::vector< string > remaining_candidate_files;
-      for (auto fib : input_candidates)
-      {
-        if (fib!=best_candidate)
-        {
-          remaining_candidates.push_back(fib);
-          remaining_candidate_files.push_back(candidate_tract_files.at(i));
-        }
-        else
-          name = ist::GetFilenameWithoutExtension(candidate_tract_files.at(i));
-        ++i;
-      }
-      input_candidates = remaining_candidates;
-      candidate_tract_files = remaining_candidate_files;
-
-      iteration++;
-      mitk::IOUtil::Save(best_candidate, outRoot + boost::lexical_cast<string>(iteration) + "_" + name + ".fib");
-      writer->SetInput(peak_image);
-      writer->SetFileName(outRoot + boost::lexical_cast<string>(iteration) + "_" + name + ".nrrd");
-      writer->Update();
-      std::cout.rdbuf (old);              // <-- restore
-
-      MITK_INFO << "Iteration: " << iteration;
-      MITK_INFO << std::fixed << "Coverage: " << setprecision(2) << 100.0*coverage << "% (+" << 100*(1.0-coverage) * next_coverage << "%)";
-    }
-
-    clock.Stop();
-    int h = clock.GetTotal()/3600;
-    int m = ((int)clock.GetTotal()%3600)/60;
-    int s = (int)clock.GetTotal()%60;
-    MITK_INFO << "Plausibility estimation took " << h << "h, " << m << "m and " << s << "s";
-  }
-  catch (itk::ExceptionObject e)
-  {
-    std::cout << e;
-    return EXIT_FAILURE;
-  }
-  catch (std::exception e)
-  {
-    std::cout << e.what();
-    return EXIT_FAILURE;
-  }
-  catch (...)
-  {
-    std::cout << "ERROR!?!";
-    return EXIT_FAILURE;
-  }
-  return EXIT_SUCCESS;
-}
diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/documentation/UserManual/QmitkFiberProcessingViewUserManual.dox b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/documentation/UserManual/QmitkFiberProcessingViewUserManual.dox
index 586d5dd171..46f70c978c 100644
--- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/documentation/UserManual/QmitkFiberProcessingViewUserManual.dox
+++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/documentation/UserManual/QmitkFiberProcessingViewUserManual.dox
@@ -1,9 +1,9 @@
 /**
 \page org_mitk_views_fiberprocessing Fiber Processing
 
-This view provides tools to extract subbundles from a given fiber bundle, to remove unwanted fibers (e.g. via length, curvature and directional constraints) and to modify the properties of a fiber bundles such as coloring or fiber sampling.
+This view provides tools to extract subbundles from a given fiber bundle, to remove unwanted fibers (e.g. via length, curvature, directional and fiber weight constraints) and to modify the properties of a fiber bundles such as coloring or fiber sampling.
 
 <b>Fiber Extraction:</b>
 Place ROIs in the 2D render widgets (cricles or polygons) and extract fibers from the bundle that pass through these ROIs by selecting the according ROI and fiber bundle in the datamanger and starting the extraction. The ROIs can be combined via logical operations. All fibers that pass through the thus generated composite ROI are extracted. The extraction can also be performed using 3D ROIs represented as binary mask images. In this extraction method, the logical operations are not implemented at the moment.
 
 */
diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberProcessingView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberProcessingView.cpp
index 3e3cee250e..e313b9abb3 100644
--- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberProcessingView.cpp
+++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberProcessingView.cpp
@@ -1,1546 +1,1577 @@
 /*===================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center,
 Division of Medical and Biological Informatics.
 All rights reserved.
 
 This software is distributed WITHOUT ANY WARRANTY; without
 even the implied warranty of MERCHANTABILITY or FITNESS FOR
 A PARTICULAR PURPOSE.
 
 See LICENSE.txt or http://www.mitk.org for details.
 
 ===================================================================*/
 
 
 // Blueberry
 #include <berryISelectionService.h>
 #include <berryIWorkbenchPart.h>
 #include <berryIWorkbenchWindow.h>
 
 // Qmitk
 #include "QmitkFiberProcessingView.h"
 
 // Qt
 #include <QMessageBox>
 
 // MITK
 #include <mitkNodePredicateProperty.h>
 #include <mitkImageCast.h>
 #include <mitkPointSet.h>
 #include <mitkPlanarCircle.h>
 #include <mitkPlanarPolygon.h>
 #include <mitkPlanarRectangle.h>
 #include <mitkPlanarFigureInteractor.h>
 #include <mitkImageAccessByItk.h>
 #include <mitkDataNodeObject.h>
 #include <mitkTensorImage.h>
 #include "usModuleRegistry.h"
 #include <itkFiberCurvatureFilter.h>
 
 #include "mitkNodePredicateDataType.h"
 #include <mitkNodePredicateProperty.h>
 #include <mitkNodePredicateAnd.h>
 #include <mitkNodePredicateNot.h>
 #include <mitkNodePredicateOr.h>
 
 // ITK
 #include <itkResampleImageFilter.h>
 #include <itkGaussianInterpolateImageFunction.h>
 #include <itkImageRegionIteratorWithIndex.h>
 #include <itkTractsToFiberEndingsImageFilter.h>
 #include <itkTractDensityImageFilter.h>
 #include <itkImageRegion.h>
 #include <itkTractsToRgbaImageFilter.h>
 
 #define _USE_MATH_DEFINES
 #include <math.h>
 
 
 const std::string QmitkFiberProcessingView::VIEW_ID = "org.mitk.views.fiberprocessing";
 const std::string id_DataManager = "org.mitk.views.datamanager";
 using namespace mitk;
 
 QmitkFiberProcessingView::QmitkFiberProcessingView()
   : QmitkAbstractView()
   , m_Controls( 0 )
   , m_CircleCounter(0)
   , m_PolygonCounter(0)
   , m_UpsamplingFactor(1)
 {
 
 }
 
 // Destructor
 QmitkFiberProcessingView::~QmitkFiberProcessingView()
 {
   RemoveObservers();
 }
 
 void QmitkFiberProcessingView::CreateQtPartControl( QWidget *parent )
 {
   // build up qt view, unless already done
   if ( !m_Controls )
   {
     // create GUI widgets from the Qt Designer's .ui file
     m_Controls = new Ui::QmitkFiberProcessingViewControls;
     m_Controls->setupUi( parent );
 
     connect( m_Controls->m_CircleButton, SIGNAL( clicked() ), this, SLOT( OnDrawCircle() ) );
     connect( m_Controls->m_PolygonButton, SIGNAL( clicked() ), this, SLOT( OnDrawPolygon() ) );
     connect(m_Controls->PFCompoANDButton, SIGNAL(clicked()), this, SLOT(GenerateAndComposite()) );
     connect(m_Controls->PFCompoORButton, SIGNAL(clicked()), this, SLOT(GenerateOrComposite()) );
     connect(m_Controls->PFCompoNOTButton, SIGNAL(clicked()), this, SLOT(GenerateNotComposite()) );
     connect(m_Controls->m_GenerateRoiImage, SIGNAL(clicked()), this, SLOT(GenerateRoiImage()) );
 
     connect(m_Controls->m_JoinBundles, SIGNAL(clicked()), this, SLOT(JoinBundles()) );
     connect(m_Controls->m_SubstractBundles, SIGNAL(clicked()), this, SLOT(SubstractBundles()) );
     connect(m_Controls->m_CopyBundle, SIGNAL(clicked()), this, SLOT(CopyBundles()) );
 
     connect(m_Controls->m_ExtractFibersButton, SIGNAL(clicked()), this, SLOT(Extract()));
     connect(m_Controls->m_RemoveButton, SIGNAL(clicked()), this, SLOT(Remove()));
     connect(m_Controls->m_ModifyButton, SIGNAL(clicked()), this, SLOT(Modify()));
 
     connect(m_Controls->m_ExtractionMethodBox, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGui()));
     connect(m_Controls->m_RemovalMethodBox, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGui()));
     connect(m_Controls->m_ModificationMethodBox, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGui()));
     connect(m_Controls->m_ExtractionBoxMask, SIGNAL(currentIndexChanged(int)), this, SLOT(OnMaskExtractionChanged()));
 
     m_Controls->m_ColorMapBox->SetDataStorage(this->GetDataStorage());
     mitk::TNodePredicateDataType<mitk::Image>::Pointer isMitkImage = mitk::TNodePredicateDataType<mitk::Image>::New();
     mitk::NodePredicateDataType::Pointer isDwi = mitk::NodePredicateDataType::New("DiffusionImage");
     mitk::NodePredicateDataType::Pointer isDti = mitk::NodePredicateDataType::New("TensorImage");
     mitk::NodePredicateDataType::Pointer isOdf = mitk::NodePredicateDataType::New("OdfImage");
     mitk::NodePredicateOr::Pointer isDiffusionImage = mitk::NodePredicateOr::New(isDwi, isDti);
     isDiffusionImage = mitk::NodePredicateOr::New(isDiffusionImage, isOdf);
     mitk::NodePredicateNot::Pointer noDiffusionImage = mitk::NodePredicateNot::New(isDiffusionImage);
     mitk::NodePredicateAnd::Pointer finalPredicate = mitk::NodePredicateAnd::New(isMitkImage, noDiffusionImage);
     m_Controls->m_ColorMapBox->SetPredicate(finalPredicate);
 
     m_Controls->label_17->setVisible(false);
     m_Controls->m_FiberExtractionFractionBox->setVisible(false);
   }
 
   UpdateGui();
 }
 
 void QmitkFiberProcessingView::OnMaskExtractionChanged()
 {
   if (m_Controls->m_ExtractionBoxMask->currentIndex() == 2)
   {
     m_Controls->label_17->setVisible(true);
     m_Controls->m_FiberExtractionFractionBox->setVisible(true);
     m_Controls->m_BothEnds->setVisible(false);
   }
   else
   {
     m_Controls->label_17->setVisible(false);
     m_Controls->m_FiberExtractionFractionBox->setVisible(false);
     if (m_Controls->m_ExtractionBoxMask->currentIndex() != 3)
       m_Controls->m_BothEnds->setVisible(true);
   }
 }
 
 void QmitkFiberProcessingView::SetFocus()
 {
   m_Controls->toolBoxx->setFocus();
 }
 
 void QmitkFiberProcessingView::Modify()
 {
   switch (m_Controls->m_ModificationMethodBox->currentIndex())
   {
   case 0:
   {
     ResampleSelectedBundlesSpline();
     break;
   }
   case 1:
   {
     ResampleSelectedBundlesLinear();
     break;
   }
   case 2:
   {
     CompressSelectedBundles();
     break;
   }
   case 3:
   {
     DoImageColorCoding();
     break;
   }
   case 4:
   {
     MirrorFibers();
     break;
   }
   case 5:
   {
     WeightFibers();
     break;
   }
   case 6:
   {
     DoCurvatureColorCoding();
     break;
   }
   case 7:
   {
     DoWeightColorCoding();
     break;
   }
   }
 }
 
 void QmitkFiberProcessingView::WeightFibers()
 {
   float weight = this->m_Controls->m_BundleWeightBox->value();
   for (auto node : m_SelectedFB)
   {
     mitk::FiberBundle::Pointer fib = dynamic_cast<mitk::FiberBundle*>(node->GetData());
     fib->SetFiberWeights(weight);
   }
 
 }
 
 void QmitkFiberProcessingView::Remove()
 {
   switch (m_Controls->m_RemovalMethodBox->currentIndex())
   {
   case 0:
   {
     RemoveDir();
     break;
   }
   case 1:
   {
     PruneBundle();
     break;
   }
   case 2:
   {
     ApplyCurvatureThreshold();
     break;
   }
   case 3:
   {
     RemoveWithMask(false);
     break;
   }
   case 4:
   {
     RemoveWithMask(true);
     break;
   }
+  case 5:
+  {
+    ApplyWeightThreshold();
+    break;
+  }
   }
 }
 
 void QmitkFiberProcessingView::Extract()
 {
   switch (m_Controls->m_ExtractionMethodBox->currentIndex())
   {
   case 0:
   {
     ExtractWithPlanarFigure();
     break;
   }
   case 1:
   {
     switch (m_Controls->m_ExtractionBoxMask->currentIndex())
     {
     {
     case 0:
         ExtractWithMask(true, false);
         break;
     }
     {
     case 1:
         ExtractWithMask(true, true);
         break;
     }
     {
     case 2:
         ExtractWithMask(false, false);
         break;
     }
     {
     case 3:
         ExtractWithMask(false, true);
         break;
     }
     }
     break;
   }
   }
 }
 
 void QmitkFiberProcessingView::PruneBundle()
 {
   int minLength = this->m_Controls->m_PruneFibersMinBox->value();
   int maxLength = this->m_Controls->m_PruneFibersMaxBox->value();
   for (auto node : m_SelectedFB)
   {
     mitk::FiberBundle::Pointer fib = dynamic_cast<mitk::FiberBundle*>(node->GetData());
     if (!fib->RemoveShortFibers(minLength))
       QMessageBox::information(nullptr, "No output generated:", "The resulting fiber bundle contains no fibers.");
     else if (!fib->RemoveLongFibers(maxLength))
       QMessageBox::information(nullptr, "No output generated:", "The resulting fiber bundle contains no fibers.");
   }
   RenderingManager::GetInstance()->RequestUpdateAll();
 }
 
+void QmitkFiberProcessingView::ApplyWeightThreshold()
+{
+  float thr = this->m_Controls->m_WeightThresholdBox->value();
+  std::vector< DataNode::Pointer > nodes = m_SelectedFB;
+  for (auto node : nodes)
+  {
+    mitk::FiberBundle::Pointer fib = dynamic_cast<mitk::FiberBundle*>(node->GetData());
+
+    mitk::FiberBundle::Pointer newFib = fib->FilterByWeights(thr);
+    if (newFib->GetNumFibers()>0)
+    {
+      newFib->ColorFibersByFiberWeights(false, true);
+      node->SetData(newFib);
+    }
+    else
+      QMessageBox::information(nullptr, "No output generated:", "The resulting fiber bundle contains no fibers.");
+  }
+  RenderingManager::GetInstance()->RequestUpdateAll();
+}
+
 void QmitkFiberProcessingView::ApplyCurvatureThreshold()
 {
   int angle = this->m_Controls->m_CurvSpinBox->value();
   int dist = this->m_Controls->m_CurvDistanceSpinBox->value();
   std::vector< DataNode::Pointer > nodes = m_SelectedFB;
   for (auto node : nodes)
   {
     mitk::FiberBundle::Pointer fib = dynamic_cast<mitk::FiberBundle*>(node->GetData());
 
     itk::FiberCurvatureFilter::Pointer filter = itk::FiberCurvatureFilter::New();
     filter->SetInputFiberBundle(fib);
     filter->SetAngularDeviation(angle);
     filter->SetDistance(dist);
     filter->SetRemoveFibers(m_Controls->m_RemoveCurvedFibersBox->isChecked());
     filter->Update();
     mitk::FiberBundle::Pointer newFib = filter->GetOutputFiberBundle();
     if (newFib->GetNumFibers()>0)
     {
       newFib->ColorFibersByOrientation();
       node->SetData(newFib);
     }
     else
       QMessageBox::information(nullptr, "No output generated:", "The resulting fiber bundle contains no fibers.");
   }
   RenderingManager::GetInstance()->RequestUpdateAll();
 }
 
 void QmitkFiberProcessingView::RemoveDir()
 {
   for (auto node : m_SelectedFB)
   {
     mitk::FiberBundle::Pointer fib = dynamic_cast<mitk::FiberBundle*>(node->GetData());
     vnl_vector_fixed<double,3> dir;
     dir[0] = m_Controls->m_ExtractDirX->value();
     dir[1] = m_Controls->m_ExtractDirY->value();
     dir[2] = m_Controls->m_ExtractDirZ->value();
     fib->RemoveDir(dir,cos((float)m_Controls->m_ExtractAngle->value()*M_PI/180));
   }
   RenderingManager::GetInstance()->RequestUpdateAll();
 }
 
 void QmitkFiberProcessingView::RemoveWithMask(bool removeInside)
 {
   if (m_MaskImageNode.IsNull())
     return;
 
   mitk::Image::Pointer mitkMask = dynamic_cast<mitk::Image*>(m_MaskImageNode->GetData());
   for (auto node : m_SelectedFB)
   {
     mitk::FiberBundle::Pointer fib = dynamic_cast<mitk::FiberBundle*>(node->GetData());
 
     itkUCharImageType::Pointer mask = itkUCharImageType::New();
     mitk::CastToItkImage(mitkMask, mask);
     mitk::FiberBundle::Pointer newFib = fib->RemoveFibersOutside(mask, removeInside);
     if (newFib->GetNumFibers()<=0)
     {
       QMessageBox::information(nullptr, "No output generated:", "The resulting fiber bundle contains no fibers.");
       continue;
     }
     node->SetData(newFib);
   }
   RenderingManager::GetInstance()->RequestUpdateAll();
 }
 
 void QmitkFiberProcessingView::ExtractWithMask(bool onlyEnds, bool invert)
 {
   if (m_MaskImageNode.IsNull())
     return;
 
   mitk::Image::Pointer mitkMask = dynamic_cast<mitk::Image*>(m_MaskImageNode->GetData());
   for (auto node : m_SelectedFB)
   {
     mitk::FiberBundle::Pointer fib = dynamic_cast<mitk::FiberBundle*>(node->GetData());
     QString name(node->GetName().c_str());
 
     itkUCharImageType::Pointer mask = itkUCharImageType::New();
     mitk::CastToItkImage(mitkMask, mask);
     mitk::FiberBundle::Pointer newFib = fib->ExtractFiberSubset(mask, !onlyEnds, invert, m_Controls->m_BothEnds->isChecked(), m_Controls->m_FiberExtractionFractionBox->value());
     if (newFib->GetNumFibers()<=0)
     {
       QMessageBox::information(nullptr, "No output generated:", "The resulting fiber bundle contains no fibers.");
       continue;
     }
 
     DataNode::Pointer newNode = DataNode::New();
     newNode->SetData(newFib);
 
     if (invert)
     {
       name += "_not";
 
       if (onlyEnds)
         name += "-ending-in-mask";
       else
         name += "-passing-mask";
     }
     else
     {
       if (onlyEnds)
         name += "_ending-in-mask";
       else
         name += "_passing-mask";
     }
 
     newNode->SetName(name.toStdString());
     GetDataStorage()->Add(newNode);
     node->SetVisibility(false);
   }
 }
 
 void QmitkFiberProcessingView::GenerateRoiImage()
 {
   if (m_SelectedPF.empty())
     return;
 
   mitk::BaseGeometry::Pointer geometry;
   if (!m_SelectedFB.empty())
   {
     mitk::FiberBundle::Pointer fib = dynamic_cast<mitk::FiberBundle*>(m_SelectedFB.front()->GetData());
     geometry = fib->GetGeometry();
   }
   else if (m_SelectedImage)
     geometry = m_SelectedImage->GetGeometry();
   else
     return;
 
   itk::Vector<double,3> spacing = geometry->GetSpacing();
   spacing /= m_UpsamplingFactor;
 
   mitk::Point3D newOrigin = geometry->GetOrigin();
   mitk::Geometry3D::BoundsArrayType bounds = geometry->GetBounds();
   newOrigin[0] += bounds.GetElement(0);
   newOrigin[1] += bounds.GetElement(2);
   newOrigin[2] += bounds.GetElement(4);
 
   itk::Matrix<double, 3, 3> direction;
   itk::ImageRegion<3> imageRegion;
   for (int i=0; i<3; i++)
     for (int j=0; j<3; j++)
       direction[j][i] = geometry->GetMatrixColumn(i)[j]/spacing[j];
   imageRegion.SetSize(0, geometry->GetExtent(0)*m_UpsamplingFactor);
   imageRegion.SetSize(1, geometry->GetExtent(1)*m_UpsamplingFactor);
   imageRegion.SetSize(2, geometry->GetExtent(2)*m_UpsamplingFactor);
 
   m_PlanarFigureImage = itkUCharImageType::New();
   m_PlanarFigureImage->SetSpacing( spacing );   // Set the image spacing
   m_PlanarFigureImage->SetOrigin( newOrigin );     // Set the image origin
   m_PlanarFigureImage->SetDirection( direction );  // Set the image direction
   m_PlanarFigureImage->SetRegions( imageRegion );
   m_PlanarFigureImage->Allocate();
   m_PlanarFigureImage->FillBuffer( 0 );
 
   Image::Pointer tmpImage = Image::New();
   tmpImage->InitializeByItk(m_PlanarFigureImage.GetPointer());
   tmpImage->SetVolume(m_PlanarFigureImage->GetBufferPointer());
 
   std::string name = m_SelectedPF.at(0)->GetName();
   WritePfToImage(m_SelectedPF.at(0), tmpImage);
   for (unsigned int i=1; i<m_SelectedPF.size(); i++)
   {
     name += "+";
     name += m_SelectedPF.at(i)->GetName();
     WritePfToImage(m_SelectedPF.at(i), tmpImage);
   }
 
   DataNode::Pointer node = DataNode::New();
   tmpImage = Image::New();
   tmpImage->InitializeByItk(m_PlanarFigureImage.GetPointer());
   tmpImage->SetVolume(m_PlanarFigureImage->GetBufferPointer());
   node->SetData(tmpImage);
   node->SetName(name);
   this->GetDataStorage()->Add(node);
 }
 
 void QmitkFiberProcessingView::WritePfToImage(mitk::DataNode::Pointer node, mitk::Image* image)
 {
   if (dynamic_cast<mitk::PlanarFigure*>(node->GetData()))
   {
     m_PlanarFigure = dynamic_cast<mitk::PlanarFigure*>(node->GetData());
     AccessFixedDimensionByItk_2(
           image,
           InternalReorientImagePlane, 3,
           m_PlanarFigure->GetGeometry(), -1);
 
     AccessFixedDimensionByItk_2(
           m_InternalImage,
           InternalCalculateMaskFromPlanarFigure,
           3, 2, node->GetName() );
   }
   else if (dynamic_cast<mitk::PlanarFigureComposite*>(node->GetData()))
   {
     DataStorage::SetOfObjects::ConstPointer children = GetDataStorage()->GetDerivations(node);
     for (unsigned int i=0; i<children->Size(); i++)
     {
       WritePfToImage(children->at(i), image);
     }
   }
 }
 
 template < typename TPixel, unsigned int VImageDimension >
 void QmitkFiberProcessingView::InternalReorientImagePlane( const itk::Image< TPixel, VImageDimension > *image, mitk::BaseGeometry* planegeo3D, int additionalIndex )
 {
   typedef itk::Image< TPixel, VImageDimension > ImageType;
   typedef itk::Image< float, VImageDimension > FloatImageType;
 
   typedef itk::ResampleImageFilter<ImageType, FloatImageType, double> ResamplerType;
   typename ResamplerType::Pointer resampler = ResamplerType::New();
 
   mitk::PlaneGeometry* planegeo = dynamic_cast<mitk::PlaneGeometry*>(planegeo3D);
 
   float upsamp = m_UpsamplingFactor;
   float gausssigma = 0.5;
 
   // Spacing
   typename ResamplerType::SpacingType spacing = planegeo->GetSpacing();
   spacing[0] = image->GetSpacing()[0] / upsamp;
   spacing[1] = image->GetSpacing()[1] / upsamp;
   spacing[2] = image->GetSpacing()[2];
   resampler->SetOutputSpacing( spacing );
 
   // Size
   typename ResamplerType::SizeType size;
   size[0] = planegeo->GetExtentInMM(0) / spacing[0];
   size[1] = planegeo->GetExtentInMM(1) / spacing[1];
   size[2] = 1;
   resampler->SetSize( size );
 
   // Origin
   typename mitk::Point3D orig = planegeo->GetOrigin();
   typename mitk::Point3D corrorig;
   planegeo3D->WorldToIndex(orig,corrorig);
   corrorig[0] += 0.5/upsamp;
   corrorig[1] += 0.5/upsamp;
   corrorig[2] += 0;
   planegeo3D->IndexToWorld(corrorig,corrorig);
   resampler->SetOutputOrigin(corrorig );
 
   // Direction
   typename ResamplerType::DirectionType direction;
   typename mitk::AffineTransform3D::MatrixType matrix = planegeo->GetIndexToWorldTransform()->GetMatrix();
   for(unsigned int c=0; c<matrix.ColumnDimensions; c++)
   {
     double sum = 0;
     for(unsigned int r=0; r<matrix.RowDimensions; r++)
       sum += matrix(r,c)*matrix(r,c);
     for(unsigned int r=0; r<matrix.RowDimensions; r++)
       direction(r,c) = matrix(r,c)/sqrt(sum);
   }
   resampler->SetOutputDirection( direction );
 
   // Gaussian interpolation
   if(gausssigma != 0)
   {
     double sigma[3];
     for( unsigned int d = 0; d < 3; d++ )
       sigma[d] = gausssigma * image->GetSpacing()[d];
     double alpha = 2.0;
     typedef itk::GaussianInterpolateImageFunction<ImageType, double> GaussianInterpolatorType;
     typename GaussianInterpolatorType::Pointer interpolator = GaussianInterpolatorType::New();
     interpolator->SetInputImage( image );
     interpolator->SetParameters( sigma, alpha );
     resampler->SetInterpolator( interpolator );
   }
   else
   {
     typedef typename itk::LinearInterpolateImageFunction<ImageType, double> InterpolatorType;
     typename InterpolatorType::Pointer interpolator = InterpolatorType::New();
     interpolator->SetInputImage( image );
     resampler->SetInterpolator( interpolator );
   }
 
   resampler->SetInput( image );
   resampler->SetDefaultPixelValue(0);
   resampler->Update();
 
   if(additionalIndex < 0)
   {
     this->m_InternalImage = mitk::Image::New();
     this->m_InternalImage->InitializeByItk( resampler->GetOutput() );
     this->m_InternalImage->SetVolume( resampler->GetOutput()->GetBufferPointer() );
   }
 }
 
 template < typename TPixel, unsigned int VImageDimension >
 void QmitkFiberProcessingView::InternalCalculateMaskFromPlanarFigure( itk::Image< TPixel, VImageDimension > *image, unsigned int axis, std::string )
 {
   typedef itk::Image< TPixel, VImageDimension > ImageType;
   typedef itk::CastImageFilter< ImageType, itkUCharImageType > CastFilterType;
 
   // Generate mask image as new image with same header as input image and
   // initialize with "1".
   itkUCharImageType::Pointer newMaskImage = itkUCharImageType::New();
   newMaskImage->SetSpacing( image->GetSpacing() );   // Set the image spacing
   newMaskImage->SetOrigin( image->GetOrigin() );     // Set the image origin
   newMaskImage->SetDirection( image->GetDirection() );  // Set the image direction
   newMaskImage->SetRegions( image->GetLargestPossibleRegion() );
   newMaskImage->Allocate();
   newMaskImage->FillBuffer( 1 );
 
   // Generate VTK polygon from (closed) PlanarFigure polyline
   // (The polyline points are shifted by -0.5 in z-direction to make sure
   // that the extrusion filter, which afterwards elevates all points by +0.5
   // in z-direction, creates a 3D object which is cut by the the plane z=0)
   const PlaneGeometry *planarFigurePlaneGeometry = m_PlanarFigure->GetPlaneGeometry();
   const PlanarFigure::PolyLineType planarFigurePolyline = m_PlanarFigure->GetPolyLine( 0 );
   const BaseGeometry *imageGeometry3D = m_InternalImage->GetGeometry( 0 );
 
   vtkPolyData *polyline = vtkPolyData::New();
   polyline->Allocate( 1, 1 );
 
   // Determine x- and y-dimensions depending on principal axis
   int i0, i1;
   switch ( axis )
   {
   case 0:
     i0 = 1;
     i1 = 2;
     break;
   case 1:
     i0 = 0;
     i1 = 2;
     break;
   case 2:
   default:
     i0 = 0;
     i1 = 1;
     break;
   }
 
   // Create VTK polydata object of polyline contour
   vtkPoints *points = vtkPoints::New();
   PlanarFigure::PolyLineType::const_iterator it;
   unsigned int numberOfPoints = 0;
 
   for ( it = planarFigurePolyline.begin(); it != planarFigurePolyline.end(); ++it )
   {
     Point3D point3D;
 
     // Convert 2D point back to the local index coordinates of the selected image
     Point2D point2D = *it;
     planarFigurePlaneGeometry->WorldToIndex(point2D, point2D);
     point2D[0] -= 0.5/m_UpsamplingFactor;
     point2D[1] -= 0.5/m_UpsamplingFactor;
     planarFigurePlaneGeometry->IndexToWorld(point2D, point2D);
     planarFigurePlaneGeometry->Map( point2D, point3D );
 
     // Polygons (partially) outside of the image bounds can not be processed further due to a bug in vtkPolyDataToImageStencil
     if ( !imageGeometry3D->IsInside( point3D ) )
     {
       float bounds[2] = {0,0};
       bounds[0] =
           this->m_InternalImage->GetLargestPossibleRegion().GetSize().GetElement(i0);
       bounds[1] =
           this->m_InternalImage->GetLargestPossibleRegion().GetSize().GetElement(i1);
 
       imageGeometry3D->WorldToIndex( point3D, point3D );
 
       if (point3D[i0]<0)
         point3D[i0] = 0.0;
       else if (point3D[i0]>bounds[0])
         point3D[i0] = bounds[0]-0.001;
 
       if (point3D[i1]<0)
         point3D[i1] = 0.0;
       else if (point3D[i1]>bounds[1])
         point3D[i1] = bounds[1]-0.001;
 
       points->InsertNextPoint( point3D[i0], point3D[i1], -0.5 );
       numberOfPoints++;
     }
     else
     {
       imageGeometry3D->WorldToIndex( point3D, point3D );
       // Add point to polyline array
       points->InsertNextPoint( point3D[i0], point3D[i1], -0.5 );
       numberOfPoints++;
     }
   }
   polyline->SetPoints( points );
   points->Delete();
 
   vtkIdType *ptIds = new vtkIdType[numberOfPoints];
   for ( vtkIdType i = 0; i < numberOfPoints; ++i )
     ptIds[i] = i;
   polyline->InsertNextCell( VTK_POLY_LINE, numberOfPoints, ptIds );
 
   // Extrude the generated contour polygon
   vtkLinearExtrusionFilter *extrudeFilter = vtkLinearExtrusionFilter::New();
   extrudeFilter->SetInputData( polyline );
   extrudeFilter->SetScaleFactor( 1 );
   extrudeFilter->SetExtrusionTypeToNormalExtrusion();
   extrudeFilter->SetVector( 0.0, 0.0, 1.0 );
 
   // Make a stencil from the extruded polygon
   vtkPolyDataToImageStencil *polyDataToImageStencil = vtkPolyDataToImageStencil::New();
   polyDataToImageStencil->SetInputConnection( extrudeFilter->GetOutputPort() );
 
   // Export from ITK to VTK (to use a VTK filter)
   typedef itk::VTKImageImport< itkUCharImageType > ImageImportType;
   typedef itk::VTKImageExport< itkUCharImageType > ImageExportType;
 
   typename ImageExportType::Pointer itkExporter = ImageExportType::New();
   itkExporter->SetInput( newMaskImage );
 
   vtkImageImport *vtkImporter = vtkImageImport::New();
   this->ConnectPipelines( itkExporter, vtkImporter );
   vtkImporter->Update();
 
   // Apply the generated image stencil to the input image
   vtkImageStencil *imageStencilFilter = vtkImageStencil::New();
   imageStencilFilter->SetInputConnection( vtkImporter->GetOutputPort() );
   imageStencilFilter->SetStencilConnection(polyDataToImageStencil->GetOutputPort() );
   imageStencilFilter->ReverseStencilOff();
   imageStencilFilter->SetBackgroundValue( 0 );
   imageStencilFilter->Update();
 
   // Export from VTK back to ITK
   vtkImageExport *vtkExporter = vtkImageExport::New();
   vtkExporter->SetInputConnection( imageStencilFilter->GetOutputPort() );
   vtkExporter->Update();
 
   typename ImageImportType::Pointer itkImporter = ImageImportType::New();
   this->ConnectPipelines( vtkExporter, itkImporter );
   itkImporter->Update();
 
   // calculate cropping bounding box
   m_InternalImageMask3D = itkImporter->GetOutput();
   m_InternalImageMask3D->SetDirection(image->GetDirection());
 
   itk::ImageRegionConstIterator<itkUCharImageType>
       itmask(m_InternalImageMask3D, m_InternalImageMask3D->GetLargestPossibleRegion());
   itk::ImageRegionIterator<ImageType>
       itimage(image, image->GetLargestPossibleRegion());
 
   itmask.GoToBegin();
   itimage.GoToBegin();
 
   typename ImageType::SizeType lowersize = {{itk::NumericTraits<unsigned long>::max(),itk::NumericTraits<unsigned long>::max(),itk::NumericTraits<unsigned long>::max()}};
   typename ImageType::SizeType uppersize = {{0,0,0}};
   while( !itmask.IsAtEnd() )
   {
     if(itmask.Get() == 0)
       itimage.Set(0);
     else
     {
       typename ImageType::IndexType index = itimage.GetIndex();
       typename ImageType::SizeType signedindex;
       signedindex[0] = index[0];
       signedindex[1] = index[1];
       signedindex[2] = index[2];
 
       lowersize[0] = signedindex[0] < lowersize[0] ? signedindex[0] : lowersize[0];
       lowersize[1] = signedindex[1] < lowersize[1] ? signedindex[1] : lowersize[1];
       lowersize[2] = signedindex[2] < lowersize[2] ? signedindex[2] : lowersize[2];
 
       uppersize[0] = signedindex[0] > uppersize[0] ? signedindex[0] : uppersize[0];
       uppersize[1] = signedindex[1] > uppersize[1] ? signedindex[1] : uppersize[1];
       uppersize[2] = signedindex[2] > uppersize[2] ? signedindex[2] : uppersize[2];
     }
 
     ++itmask;
     ++itimage;
   }
 
   typename ImageType::IndexType index;
   index[0] = lowersize[0];
   index[1] = lowersize[1];
   index[2] = lowersize[2];
 
   typename ImageType::SizeType size;
   size[0] = uppersize[0] - lowersize[0] + 1;
   size[1] = uppersize[1] - lowersize[1] + 1;
   size[2] = uppersize[2] - lowersize[2] + 1;
 
   itk::ImageRegion<3> cropRegion = itk::ImageRegion<3>(index, size);
 
   // crop internal mask
   typedef itk::RegionOfInterestImageFilter< itkUCharImageType, itkUCharImageType > ROIMaskFilterType;
   typename ROIMaskFilterType::Pointer roi2 = ROIMaskFilterType::New();
   roi2->SetRegionOfInterest(cropRegion);
   roi2->SetInput(m_InternalImageMask3D);
   roi2->Update();
   m_InternalImageMask3D = roi2->GetOutput();
 
   Image::Pointer tmpImage = Image::New();
   tmpImage->InitializeByItk(m_InternalImageMask3D.GetPointer());
   tmpImage->SetVolume(m_InternalImageMask3D->GetBufferPointer());
 
   Image::Pointer tmpImage2 = Image::New();
   tmpImage2->InitializeByItk(m_PlanarFigureImage.GetPointer());
   const BaseGeometry *pfImageGeometry3D = tmpImage2->GetGeometry( 0 );
 
   const BaseGeometry *intImageGeometry3D = tmpImage->GetGeometry( 0 );
 
   typedef itk::ImageRegionIteratorWithIndex<itkUCharImageType> IteratorType;
   IteratorType imageIterator (m_InternalImageMask3D, m_InternalImageMask3D->GetRequestedRegion());
   imageIterator.GoToBegin();
   while ( !imageIterator.IsAtEnd() )
   {
     unsigned char val = imageIterator.Value();
     if (val>0)
     {
       itk::Index<3> index = imageIterator.GetIndex();
       Point3D point;
       point[0] = index[0];
       point[1] = index[1];
       point[2] = index[2];
 
       intImageGeometry3D->IndexToWorld(point, point);
       pfImageGeometry3D->WorldToIndex(point, point);
 
       point[i0] += 0.5;
       point[i1] += 0.5;
 
       index[0] = point[0];
       index[1] = point[1];
       index[2] = point[2];
 
       if (pfImageGeometry3D->IsIndexInside(index))
         m_PlanarFigureImage->SetPixel(index, 1);
     }
     ++imageIterator;
   }
 
   // Clean up VTK objects
   polyline->Delete();
   extrudeFilter->Delete();
   polyDataToImageStencil->Delete();
   vtkImporter->Delete();
   imageStencilFilter->Delete();
   //vtkExporter->Delete(); // TODO: crashes when outcommented; memory leak??
   delete[] ptIds;
 }
 
 void QmitkFiberProcessingView::UpdateGui()
 {
   m_Controls->m_FibLabel->setText("<font color='red'>mandatory</font>");
   m_Controls->m_PfLabel->setText("<font color='grey'>needed for extraction</font>");
   m_Controls->m_InputData->setTitle("Please Select Input Data");
 
   m_Controls->m_RemoveButton->setEnabled(false);
 
   m_Controls->m_PlanarFigureButtonsFrame->setEnabled(false);
   m_Controls->PFCompoANDButton->setEnabled(false);
   m_Controls->PFCompoORButton->setEnabled(false);
   m_Controls->PFCompoNOTButton->setEnabled(false);
 
   m_Controls->m_GenerateRoiImage->setEnabled(false);
   m_Controls->m_ExtractFibersButton->setEnabled(false);
   m_Controls->m_ModifyButton->setEnabled(false);
 
   m_Controls->m_CopyBundle->setEnabled(false);
   m_Controls->m_JoinBundles->setEnabled(false);
   m_Controls->m_SubstractBundles->setEnabled(false);
 
   // disable alle frames
   m_Controls->m_BundleWeightFrame->setVisible(false);
   m_Controls->m_ExtactionFramePF->setVisible(false);
   m_Controls->m_RemoveDirectionFrame->setVisible(false);
   m_Controls->m_RemoveLengthFrame->setVisible(false);
   m_Controls->m_RemoveCurvatureFrame->setVisible(false);
+  m_Controls->m_RemoveByWeightFrame->setVisible(false);
   m_Controls->m_SmoothFibersFrame->setVisible(false);
   m_Controls->m_CompressFibersFrame->setVisible(false);
   m_Controls->m_ColorFibersFrame->setVisible(false);
   m_Controls->m_MirrorFibersFrame->setVisible(false);
   m_Controls->m_MaskExtractionFrame->setVisible(false);
   m_Controls->m_ColorMapBox->setVisible(false);
 
   bool pfSelected = !m_SelectedPF.empty();
   bool fibSelected = !m_SelectedFB.empty();
   bool multipleFibsSelected = (m_SelectedFB.size()>1);
   bool maskSelected = m_MaskImageNode.IsNotNull();
   bool imageSelected = m_SelectedImage.IsNotNull();
 
   // toggle visibility of elements according to selected method
   switch ( m_Controls->m_ExtractionMethodBox->currentIndex() )
   {
   case 0:
     m_Controls->m_ExtactionFramePF->setVisible(true);
     break;
   case 1:
     m_Controls->m_MaskExtractionFrame->setVisible(true);
     break;
   }
 
   switch ( m_Controls->m_RemovalMethodBox->currentIndex() )
   {
   case 0:
     m_Controls->m_RemoveDirectionFrame->setVisible(true);
     if ( fibSelected )
       m_Controls->m_RemoveButton->setEnabled(true);
     break;
   case 1:
     m_Controls->m_RemoveLengthFrame->setVisible(true);
     if ( fibSelected )
       m_Controls->m_RemoveButton->setEnabled(true);
     break;
   case 2:
     m_Controls->m_RemoveCurvatureFrame->setVisible(true);
     if ( fibSelected )
       m_Controls->m_RemoveButton->setEnabled(true);
     break;
   case 3:
     break;
   case 4:
     break;
+  case 5:
+    m_Controls->m_RemoveByWeightFrame->setVisible(true);
+    if ( fibSelected )
+      m_Controls->m_RemoveButton->setEnabled(true);
+    break;
   }
 
   switch ( m_Controls->m_ModificationMethodBox->currentIndex() )
   {
   case 0:
     m_Controls->m_SmoothFibersFrame->setVisible(true);
     break;
   case 1:
     m_Controls->m_SmoothFibersFrame->setVisible(true);
     break;
   case 2:
     m_Controls->m_CompressFibersFrame->setVisible(true);
     break;
   case 3:
     m_Controls->m_ColorFibersFrame->setVisible(true);
     m_Controls->m_ColorMapBox->setVisible(true);
     break;
   case 4:
     m_Controls->m_MirrorFibersFrame->setVisible(true);
     if (m_SelectedSurfaces.size()>0)
       m_Controls->m_ModifyButton->setEnabled(true);
     break;
   case 5:
     m_Controls->m_BundleWeightFrame->setVisible(true);
     break;
   case 6:
     m_Controls->m_ColorFibersFrame->setVisible(true);
     break;
   case 7:
     m_Controls->m_ColorFibersFrame->setVisible(true);
     break;
   }
 
   // are fiber bundles selected?
   if ( fibSelected )
   {
     m_Controls->m_CopyBundle->setEnabled(true);
     m_Controls->m_ModifyButton->setEnabled(true);
     m_Controls->m_PlanarFigureButtonsFrame->setEnabled(true);
     m_Controls->m_FibLabel->setText(QString(m_SelectedFB.at(0)->GetName().c_str()));
 
     // one bundle and one planar figure needed to extract fibers
     if (pfSelected && m_Controls->m_ExtractionMethodBox->currentIndex()==0)
     {
       m_Controls->m_InputData->setTitle("Input Data");
       m_Controls->m_PfLabel->setText(QString(m_SelectedPF.at(0)->GetName().c_str()));
       m_Controls->m_ExtractFibersButton->setEnabled(true);
     }
 
     // more than two bundles needed to join/subtract
     if (multipleFibsSelected)
     {
       m_Controls->m_FibLabel->setText("multiple bundles selected");
 
       m_Controls->m_JoinBundles->setEnabled(true);
       m_Controls->m_SubstractBundles->setEnabled(true);
     }
 
     if (maskSelected && m_Controls->m_ExtractionMethodBox->currentIndex()==1)
     {
       m_Controls->m_InputData->setTitle("Input Data");
       m_Controls->m_PfLabel->setText(QString(m_MaskImageNode->GetName().c_str()));
       m_Controls->m_ExtractFibersButton->setEnabled(true);
     }
 
     if (maskSelected && (m_Controls->m_RemovalMethodBox->currentIndex()==3 || m_Controls->m_RemovalMethodBox->currentIndex()==4) )
     {
       m_Controls->m_InputData->setTitle("Input Data");
       m_Controls->m_PfLabel->setText(QString(m_MaskImageNode->GetName().c_str()));
       m_Controls->m_RemoveButton->setEnabled(true);
     }
   }
 
   // are planar figures selected?
   if (pfSelected)
   {
     if ( fibSelected || m_SelectedImage.IsNotNull())
       m_Controls->m_GenerateRoiImage->setEnabled(true);
 
     if (m_SelectedPF.size() > 1)
     {
       m_Controls->PFCompoANDButton->setEnabled(true);
       m_Controls->PFCompoORButton->setEnabled(true);
     }
     else
       m_Controls->PFCompoNOTButton->setEnabled(true);
   }
 
   // is image selected
   if (imageSelected || maskSelected)
   {
     m_Controls->m_PlanarFigureButtonsFrame->setEnabled(true);
   }
 }
 
 void QmitkFiberProcessingView::NodeRemoved(const mitk::DataNode* node )
 {
   for (auto fnode: m_SelectedFB)
     if (node == fnode)
     {
       m_SelectedFB.clear();
       break;
     }
 
   berry::IWorkbenchPart::Pointer nullPart;
   QList<mitk::DataNode::Pointer> nodes;
   OnSelectionChanged(nullPart, nodes);
 }
 
 void QmitkFiberProcessingView::NodeAdded(const mitk::DataNode* )
 {
   if (!m_Controls->m_InteractiveBox->isChecked())
   {
     berry::IWorkbenchPart::Pointer nullPart;
     QList<mitk::DataNode::Pointer> nodes;
     OnSelectionChanged(nullPart, nodes);
   }
 }
 
 void QmitkFiberProcessingView::OnEndInteraction()
 {
   if (m_Controls->m_InteractiveBox->isChecked())
     ExtractWithPlanarFigure(true);
 }
 
 void QmitkFiberProcessingView::AddObservers()
 {
   typedef itk::SimpleMemberCommand< QmitkFiberProcessingView > SimpleCommandType;
   for (auto node : m_SelectedPF)
   {
     mitk::PlanarFigure* figure = dynamic_cast<mitk::PlanarFigure*>(node->GetData());
     if (figure!=nullptr)
     {
       figure->RemoveAllObservers();
 
       // add observer for event when interaction with figure starts
       SimpleCommandType::Pointer endInteractionCommand = SimpleCommandType::New();
       endInteractionCommand->SetCallbackFunction( this, &QmitkFiberProcessingView::OnEndInteraction);
       m_EndInteractionObserverTag = figure->AddObserver( mitk::EndInteractionPlanarFigureEvent(), endInteractionCommand );
     }
   }
 }
 
 void QmitkFiberProcessingView::RemoveObservers()
 {
   for (auto node : m_SelectedPF)
   {
     mitk::PlanarFigure* figure = dynamic_cast<mitk::PlanarFigure*>(node->GetData());
     if (figure!=nullptr)
       figure->RemoveAllObservers();
   }
 }
 
 void QmitkFiberProcessingView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList<mitk::DataNode::Pointer>& nodes)
 {
   RemoveObservers();
 
   //reset existing Vectors containing FiberBundles and PlanarFigures from a previous selection
   std::vector<mitk::DataNode::Pointer>  lastSelectedFB = m_SelectedFB;
   m_SelectedFB.clear();
   m_SelectedPF.clear();
   m_SelectedSurfaces.clear();
   m_SelectedImage = nullptr;
   m_MaskImageNode = nullptr;
 
   for (auto node: nodes)
   {
     if ( dynamic_cast<mitk::FiberBundle*>(node->GetData()) )
       m_SelectedFB.push_back(node);
     else if (dynamic_cast<mitk::PlanarPolygon*>(node->GetData()) || dynamic_cast<mitk::PlanarFigureComposite*>(node->GetData()) || dynamic_cast<mitk::PlanarCircle*>(node->GetData()))
       m_SelectedPF.push_back(node);
     else if (dynamic_cast<mitk::Image*>(node->GetData()))
     {
       m_SelectedImage = dynamic_cast<mitk::Image*>(node->GetData());
       bool isBinary = false;
       node->GetPropertyValue<bool>("binary", isBinary);
       if (isBinary)
         m_MaskImageNode = node;
     }
     else if (dynamic_cast<mitk::Surface*>(node->GetData()))
       m_SelectedSurfaces.push_back(dynamic_cast<mitk::Surface*>(node->GetData()));
   }
 
   // if we perform interactive fiber extraction, we want to avoid auto-selection of the extracted bundle
   if (m_SelectedFB.empty() && m_Controls->m_InteractiveBox->isChecked())
     m_SelectedFB = lastSelectedFB;
 
   // if no fibers or surfaces are selected, select topmost
   if (m_SelectedFB.empty() && m_SelectedSurfaces.empty())
   {
     int maxLayer = 0;
     itk::VectorContainer<unsigned int, mitk::DataNode::Pointer>::ConstPointer nodes = this->GetDataStorage()->GetAll();
     for (unsigned int i=0; i<nodes->Size(); i++)
       if (dynamic_cast<mitk::FiberBundle*>(nodes->at(i)->GetData()))
       {
         mitk::DataStorage::SetOfObjects::ConstPointer sources = GetDataStorage()->GetSources(nodes->at(i));
         if (sources->Size()>0)
           continue;
 
         int layer = 0;
         nodes->at(i)->GetPropertyValue("layer", layer);
         if (layer>=maxLayer)
         {
           maxLayer = layer;
           m_SelectedFB.clear();
           m_SelectedFB.push_back(nodes->at(i));
         }
       }
   }
 
   // if no plar figure is selected, select topmost
   if (m_SelectedPF.empty())
   {
     int maxLayer = 0;
     itk::VectorContainer<unsigned int, mitk::DataNode::Pointer>::ConstPointer nodes = this->GetDataStorage()->GetAll();
     for (unsigned int i=0; i<nodes->Size(); i++)
       if (dynamic_cast<mitk::PlanarPolygon*>(nodes->at(i)->GetData()) || dynamic_cast<mitk::PlanarFigureComposite*>(nodes->at(i)->GetData()) || dynamic_cast<mitk::PlanarCircle*>(nodes->at(i)->GetData()))
       {
         mitk::DataStorage::SetOfObjects::ConstPointer sources = GetDataStorage()->GetSources(nodes->at(i));
         if (sources->Size()>0)
           continue;
 
         int layer = 0;
         nodes->at(i)->GetPropertyValue("layer", layer);
         if (layer>=maxLayer)
         {
           maxLayer = layer;
           m_SelectedPF.clear();
           m_SelectedPF.push_back(nodes->at(i));
         }
       }
   }
 
   AddObservers();
   UpdateGui();
 }
 
 void QmitkFiberProcessingView::OnDrawPolygon()
 {
   mitk::PlanarPolygon::Pointer figure = mitk::PlanarPolygon::New();
   figure->ClosedOn();
   this->AddFigureToDataStorage(figure, QString("Polygon%1").arg(++m_PolygonCounter));
 }
 
 void QmitkFiberProcessingView::OnDrawCircle()
 {
   mitk::PlanarCircle::Pointer figure = mitk::PlanarCircle::New();
   this->AddFigureToDataStorage(figure, QString("Circle%1").arg(++m_CircleCounter));
 }
 
 void QmitkFiberProcessingView::AddFigureToDataStorage(mitk::PlanarFigure* figure, const QString& name, const char *, mitk::BaseProperty* )
 {
   // initialize figure's geometry with empty geometry
   mitk::PlaneGeometry::Pointer emptygeometry = mitk::PlaneGeometry::New();
   figure->SetPlaneGeometry( emptygeometry );
 
   //set desired data to DataNode where Planarfigure is stored
   mitk::DataNode::Pointer newNode = mitk::DataNode::New();
   newNode->SetName(name.toStdString());
   newNode->SetData(figure);
   newNode->SetBoolProperty("planarfigure.3drendering", true);
   newNode->SetBoolProperty("planarfigure.3drendering.fill", true);
 
   mitk::PlanarFigureInteractor::Pointer figureInteractor = dynamic_cast<mitk::PlanarFigureInteractor*>(newNode->GetDataInteractor().GetPointer());
   if(figureInteractor.IsNull())
   {
     figureInteractor = mitk::PlanarFigureInteractor::New();
     us::Module* planarFigureModule = us::ModuleRegistry::GetModule( "MitkPlanarFigure" );
     figureInteractor->LoadStateMachine("PlanarFigureInteraction.xml", planarFigureModule );
     figureInteractor->SetEventConfig( "PlanarFigureConfig.xml", planarFigureModule );
     figureInteractor->SetDataNode(newNode);
   }
 
   // figure drawn on the topmost layer / image
   GetDataStorage()->Add(newNode );
 
   RemoveObservers();
   for(unsigned int i = 0; i < m_SelectedPF.size(); i++)
     m_SelectedPF[i]->SetSelected(false);
 
   newNode->SetSelected(true);
   m_SelectedPF.clear();
   m_SelectedPF.push_back(newNode);
   AddObservers();
   UpdateGui();
 }
 
 void QmitkFiberProcessingView::ExtractWithPlanarFigure(bool interactive)
 {
   if ( m_SelectedFB.empty() || m_SelectedPF.empty() ){
     QMessageBox::information( nullptr, "Warning", "No fibe bundle selected!");
     return;
   }
 
   try
   {
     std::vector<mitk::DataNode::Pointer> fiberBundles = m_SelectedFB;
     mitk::DataNode::Pointer planarFigure = m_SelectedPF.at(0);
     for (unsigned int i=0; i<fiberBundles.size(); i++)
     {
       mitk::FiberBundle::Pointer fib = dynamic_cast<mitk::FiberBundle*>(fiberBundles.at(i)->GetData());
       mitk::FiberBundle::Pointer extFB = fib->ExtractFiberSubset(planarFigure, GetDataStorage());
 
       if (interactive && m_Controls->m_InteractiveBox->isChecked())
       {
         if (m_InteractiveNode.IsNull())
         {
           m_InteractiveNode = mitk::DataNode::New();
           QString name("Interactive");
           m_InteractiveNode->SetName(name.toStdString());
           GetDataStorage()->Add(m_InteractiveNode);
         }
         float op = 5.0/sqrt(fib->GetNumFibers());
         float currentOp = 0;
         fiberBundles.at(i)->GetFloatProperty("opacity", currentOp);
 
         if (currentOp!=op)
         {
           fib->SetFiberColors(255, 255, 255);
           fiberBundles.at(i)->SetFloatProperty("opacity", op);
           fiberBundles.at(i)->SetBoolProperty("Fiber2DfadeEFX", false);
         }
         m_InteractiveNode->SetData(extFB);
       }
       else
       {
         if (extFB->GetNumFibers()<=0)
         {
           QMessageBox::information(nullptr, "No output generated:", "The resulting fiber bundle contains no fibers.");
           continue;
         }
 
         mitk::DataNode::Pointer node;
         node = mitk::DataNode::New();
         node->SetData(extFB);
         QString name(fiberBundles.at(i)->GetName().c_str());
         name += "*";
         node->SetName(name.toStdString());
         fiberBundles.at(i)->SetVisibility(false);
         GetDataStorage()->Add(node);
       }
     }
   }
   catch(const std::out_of_range& )
   {
     QMessageBox::warning( nullptr, "Fiber extraction failed", "Did you only create the planar figure, using the circle or polygon button, but forgot to actually place it in the image afterwards? \nAfter creating a planar figure, simply left-click at the desired position in the image or on the tractogram to place it.");
   }
 }
 
 void QmitkFiberProcessingView::GenerateAndComposite()
 {
   mitk::PlanarFigureComposite::Pointer PFCAnd = mitk::PlanarFigureComposite::New();
   PFCAnd->setOperationType(mitk::PlanarFigureComposite::AND);
 
   mitk::DataNode::Pointer newPFCNode;
   newPFCNode = mitk::DataNode::New();
   newPFCNode->SetName("AND");
   newPFCNode->SetData(PFCAnd);
 
   AddCompositeToDatastorage(newPFCNode, m_SelectedPF);
   RemoveObservers();
   m_SelectedPF.clear();
   m_SelectedPF.push_back(newPFCNode);
   AddObservers();
   UpdateGui();
 }
 
 void QmitkFiberProcessingView::GenerateOrComposite()
 {
   mitk::PlanarFigureComposite::Pointer PFCOr = mitk::PlanarFigureComposite::New();
   PFCOr->setOperationType(mitk::PlanarFigureComposite::OR);
 
   mitk::DataNode::Pointer newPFCNode;
   newPFCNode = mitk::DataNode::New();
   newPFCNode->SetName("OR");
   newPFCNode->SetData(PFCOr);
 
   RemoveObservers();
   AddCompositeToDatastorage(newPFCNode, m_SelectedPF);
   m_SelectedPF.clear();
   m_SelectedPF.push_back(newPFCNode);
   UpdateGui();
 }
 
 void QmitkFiberProcessingView::GenerateNotComposite()
 {
   mitk::PlanarFigureComposite::Pointer PFCNot = mitk::PlanarFigureComposite::New();
   PFCNot->setOperationType(mitk::PlanarFigureComposite::NOT);
 
   mitk::DataNode::Pointer newPFCNode;
   newPFCNode = mitk::DataNode::New();
   newPFCNode->SetName("NOT");
   newPFCNode->SetData(PFCNot);
 
   RemoveObservers();
   AddCompositeToDatastorage(newPFCNode, m_SelectedPF);
   m_SelectedPF.clear();
   m_SelectedPF.push_back(newPFCNode);
   AddObservers();
   UpdateGui();
 }
 
 void QmitkFiberProcessingView::AddCompositeToDatastorage(mitk::DataNode::Pointer pfc, std::vector<mitk::DataNode::Pointer> children, mitk::DataNode::Pointer parentNode )
 {
   pfc->SetSelected(true);
   if (parentNode.IsNotNull())
     GetDataStorage()->Add(pfc, parentNode);
   else
     GetDataStorage()->Add(pfc);
 
   for (auto child : children)
   {
     if (dynamic_cast<PlanarFigure*>(child->GetData()))
     {
       mitk::DataNode::Pointer newChild;
       newChild = mitk::DataNode::New();
       newChild->SetData(dynamic_cast<PlanarFigure*>(child->GetData()));
       newChild->SetName( child->GetName() );
       newChild->SetBoolProperty("planarfigure.3drendering", true);
       newChild->SetBoolProperty("planarfigure.3drendering.fill", true);
 
       GetDataStorage()->Add(newChild, pfc);
       GetDataStorage()->Remove(child);
     }
     else if (dynamic_cast<PlanarFigureComposite*>(child->GetData()))
     {
       mitk::DataNode::Pointer newChild;
       newChild = mitk::DataNode::New();
       newChild->SetData(dynamic_cast<PlanarFigureComposite*>(child->GetData()));
       newChild->SetName( child->GetName() );
 
       std::vector< mitk::DataNode::Pointer > grandChildVector;
       mitk::DataStorage::SetOfObjects::ConstPointer grandchildren = GetDataStorage()->GetDerivations(child);
       for( mitk::DataStorage::SetOfObjects::const_iterator it = grandchildren->begin(); it != grandchildren->end(); ++it )
         grandChildVector.push_back(*it);
 
       AddCompositeToDatastorage(newChild, grandChildVector, pfc);
       GetDataStorage()->Remove(child);
     }
   }
   UpdateGui();
 }
 
 void QmitkFiberProcessingView::CopyBundles()
 {
   if ( m_SelectedFB.empty() ){
     QMessageBox::information( nullptr, "Warning", "Select at least one fiber bundle!");
     MITK_WARN("QmitkFiberProcessingView") << "Select at least one fiber bundle!";
     return;
   }
 
   for (auto node : m_SelectedFB)
   {
     mitk::FiberBundle::Pointer fib = dynamic_cast<mitk::FiberBundle*>(node->GetData());
     mitk::FiberBundle::Pointer newFib = fib->GetDeepCopy();
 
     node->SetVisibility(false);
     QString name("");
     name += QString(m_SelectedFB.at(0)->GetName().c_str());
     name += "_copy";
 
     mitk::DataNode::Pointer fbNode = mitk::DataNode::New();
     fbNode->SetData(newFib);
     fbNode->SetName(name.toStdString());
     fbNode->SetVisibility(true);
     GetDataStorage()->Add(fbNode);
   }
   UpdateGui();
 }
 
 void QmitkFiberProcessingView::JoinBundles()
 {
   if ( m_SelectedFB.size()<2 ){
     QMessageBox::information( nullptr, "Warning", "Select at least two fiber bundles!");
     MITK_WARN("QmitkFiberProcessingView") << "Select at least two fiber bundles!";
     return;
   }
 
   mitk::FiberBundle::Pointer newBundle = dynamic_cast<mitk::FiberBundle*>(m_SelectedFB.at(0)->GetData());
   m_SelectedFB.at(0)->SetVisibility(false);
   QString name("");
   name += QString(m_SelectedFB.at(0)->GetName().c_str());
   for (unsigned int i=1; i<m_SelectedFB.size(); i++)
   {
     newBundle = newBundle->AddBundle(dynamic_cast<mitk::FiberBundle*>(m_SelectedFB.at(i)->GetData()));
     name += "+"+QString(m_SelectedFB.at(i)->GetName().c_str());
     m_SelectedFB.at(i)->SetVisibility(false);
   }
 
   mitk::DataNode::Pointer fbNode = mitk::DataNode::New();
   fbNode->SetData(newBundle);
   fbNode->SetName(name.toStdString());
   fbNode->SetVisibility(true);
   GetDataStorage()->Add(fbNode);
   UpdateGui();
 }
 
 void QmitkFiberProcessingView::SubstractBundles()
 {
   if ( m_SelectedFB.size()<2 ){
     QMessageBox::information( nullptr, "Warning", "Select at least two fiber bundles!");
     MITK_WARN("QmitkFiberProcessingView") << "Select at least two fiber bundles!";
     return;
   }
 
   mitk::FiberBundle::Pointer newBundle = dynamic_cast<mitk::FiberBundle*>(m_SelectedFB.at(0)->GetData());
   m_SelectedFB.at(0)->SetVisibility(false);
   QString name("");
   name += QString(m_SelectedFB.at(0)->GetName().c_str());
   for (unsigned int i=1; i<m_SelectedFB.size(); i++)
   {
     newBundle = newBundle->SubtractBundle(dynamic_cast<mitk::FiberBundle*>(m_SelectedFB.at(i)->GetData()));
     if (newBundle.IsNull())
       break;
     name += "-"+QString(m_SelectedFB.at(i)->GetName().c_str());
     m_SelectedFB.at(i)->SetVisibility(false);
   }
   if (newBundle.IsNull())
   {
     QMessageBox::information(nullptr, "No output generated:", "The resulting fiber bundle contains no fibers. Did you select the fiber bundles in the correct order? X-Y is not equal to Y-X!");
     return;
   }
 
   mitk::DataNode::Pointer fbNode = mitk::DataNode::New();
   fbNode->SetData(newBundle);
   fbNode->SetName(name.toStdString());
   fbNode->SetVisibility(true);
   GetDataStorage()->Add(fbNode);
   UpdateGui();
 }
 
 void QmitkFiberProcessingView::ResampleSelectedBundlesSpline()
 {
   double factor = this->m_Controls->m_SmoothFibersBox->value();
   for (auto node : m_SelectedFB)
   {
     mitk::FiberBundle::Pointer fib = dynamic_cast<mitk::FiberBundle*>(node->GetData());
     fib->ResampleSpline(factor);
   }
   RenderingManager::GetInstance()->RequestUpdateAll();
 }
 
 void QmitkFiberProcessingView::ResampleSelectedBundlesLinear()
 {
   double factor = this->m_Controls->m_SmoothFibersBox->value();
   for (auto node : m_SelectedFB)
   {
     mitk::FiberBundle::Pointer fib = dynamic_cast<mitk::FiberBundle*>(node->GetData());
     fib->ResampleLinear(factor);
   }
   RenderingManager::GetInstance()->RequestUpdateAll();
 }
 
 void QmitkFiberProcessingView::CompressSelectedBundles()
 {
   double factor = this->m_Controls->m_ErrorThresholdBox->value();
   for (auto node : m_SelectedFB)
   {
     mitk::FiberBundle::Pointer fib = dynamic_cast<mitk::FiberBundle*>(node->GetData());
     fib->Compress(factor);
     fib->ColorFibersByOrientation();
   }
   RenderingManager::GetInstance()->RequestUpdateAll();
 }
 
 void QmitkFiberProcessingView::DoImageColorCoding()
 {
   if (m_Controls->m_ColorMapBox->GetSelectedNode().IsNull())
   {
     QMessageBox::information(nullptr, "Bundle coloring aborted:", "No image providing the scalar values for coloring the selected bundle available.");
     return;
   }
 
   for (auto node : m_SelectedFB)
   {
     mitk::FiberBundle::Pointer fib = dynamic_cast<mitk::FiberBundle*>(node->GetData());
     fib->ColorFibersByScalarMap(dynamic_cast<mitk::Image*>(m_Controls->m_ColorMapBox->GetSelectedNode()->GetData()), m_Controls->m_FiberOpacityBox->isChecked(), m_Controls->m_NormalizeColorValues->isChecked());
   }
 
   if (auto renderWindowPart = this->GetRenderWindowPart())
   {
     renderWindowPart->RequestUpdate();
   }
 }
 
 
 void QmitkFiberProcessingView::DoCurvatureColorCoding()
 {
   for (auto node : m_SelectedFB)
   {
     mitk::FiberBundle::Pointer fib = dynamic_cast<mitk::FiberBundle*>(node->GetData());
     fib->ColorFibersByCurvature(m_Controls->m_FiberOpacityBox->isChecked(), m_Controls->m_NormalizeColorValues->isChecked());
   }
 
   if (auto renderWindowPart = this->GetRenderWindowPart())
   {
     renderWindowPart->RequestUpdate();
   }
 }
 
 void QmitkFiberProcessingView::DoWeightColorCoding()
 {
   for (auto node : m_SelectedFB)
   {
     mitk::FiberBundle::Pointer fib = dynamic_cast<mitk::FiberBundle*>(node->GetData());
     fib->ColorFibersByFiberWeights(m_Controls->m_FiberOpacityBox->isChecked(), m_Controls->m_NormalizeColorValues->isChecked());
   }
 
   if (auto renderWindowPart = this->GetRenderWindowPart())
   {
     renderWindowPart->RequestUpdate();
   }
 }
 
 void QmitkFiberProcessingView::MirrorFibers()
 {
   unsigned int axis = this->m_Controls->m_MirrorFibersBox->currentIndex();
   for (auto node : m_SelectedFB)
   {
     mitk::FiberBundle::Pointer fib = dynamic_cast<mitk::FiberBundle*>(node->GetData());
     if (m_SelectedImage.IsNotNull())
       fib->SetReferenceGeometry(m_SelectedImage->GetGeometry());
     fib->MirrorFibers(axis);
   }
 
 
   for (auto surf : m_SelectedSurfaces)
   {
     vtkSmartPointer<vtkPolyData> poly = surf->GetVtkPolyData();
     vtkSmartPointer<vtkPoints> vtkNewPoints = vtkSmartPointer<vtkPoints>::New();
 
     for (int i=0; i<poly->GetNumberOfPoints(); i++)
     {
       double* point = poly->GetPoint(i);
       point[axis] *= -1;
       vtkNewPoints->InsertNextPoint(point);
     }
     poly->SetPoints(vtkNewPoints);
     surf->CalculateBoundingBox();
   }
 
   if (auto renderWindowPart = this->GetRenderWindowPart())
   {
     renderWindowPart->RequestUpdate();
   }
 }
diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberProcessingView.h b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberProcessingView.h
index 522d304afe..4651a3f7ed 100644
--- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberProcessingView.h
+++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberProcessingView.h
@@ -1,199 +1,200 @@
 /*===================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center,
 Division of Medical and Biological Informatics.
 All rights reserved.
 
 This software is distributed WITHOUT ANY WARRANTY; without
 even the implied warranty of MERCHANTABILITY or FITNESS FOR
 A PARTICULAR PURPOSE.
 
 See LICENSE.txt or http://www.mitk.org for details.
 
 ===================================================================*/
 
 #ifndef QmitkFiberProcessingView_h
 #define QmitkFiberProcessingView_h
 
 #include <QmitkAbstractView.h>
 #include "ui_QmitkFiberProcessingViewControls.h"
 
 #include <mitkPlanarFigureComposite.h>
 #include <mitkFiberBundle.h>
 #include <mitkSurface.h>
 
 #include <itkCastImageFilter.h>
 #include <itkVTKImageImport.h>
 #include <itkVTKImageExport.h>
 #include <itkRegionOfInterestImageFilter.h>
 
 #include <vtkLinearExtrusionFilter.h>
 #include <vtkPolyDataToImageStencil.h>
 #include <vtkSelectEnclosedPoints.h>
 #include <vtkImageImport.h>
 #include <vtkImageExport.h>
 #include <vtkImageStencil.h>
 #include <vtkSmartPointer.h>
 #include <vtkSelection.h>
 #include <vtkSelectionNode.h>
 #include <vtkExtractSelectedThresholds.h>
 #include <vtkFloatArray.h>
 
 /*!
 \brief View to process fiber bundles. Supplies methods to extract fibers from the bundle, fiber resampling, mirroring, join and subtract bundles and much more.
 */
 class QmitkFiberProcessingView : public QmitkAbstractView
 {
   // this is needed for all Qt objects that should have a Qt meta-object
   // (everything that derives from QObject and wants to have signal/slots)
   Q_OBJECT
 
 public:
 
   typedef itk::Image< unsigned char, 3 >    itkUCharImageType;
 
   static const std::string VIEW_ID;
 
   QmitkFiberProcessingView();
   virtual ~QmitkFiberProcessingView();
 
   virtual void CreateQtPartControl(QWidget *parent) override;
 
   ///
   /// Sets the focus to an internal widget.
   ///
   virtual void SetFocus() override;
 
 protected slots:
 
   void OnDrawCircle();          ///< add circle interactors etc.
   void OnDrawPolygon();         ///< add circle interactors etc.
   void GenerateAndComposite();
   void GenerateOrComposite();
   void GenerateNotComposite();
 
   void CopyBundles();               ///< add copies of selected bundles to data storage
   void JoinBundles();               ///< merge selected fiber bundles
   void SubstractBundles();          ///< subtract bundle A from bundle B. Not commutative! Defined by order of selection.
   void GenerateRoiImage();          ///< generate binary image of selected planar figures.
 
   void Remove();
   void Extract();
   void Modify();
   void UpdateGui();     ///< update button activity etc. dpending on current datamanager selection
   void OnMaskExtractionChanged();
 
   virtual void AddFigureToDataStorage(mitk::PlanarFigure* figure, const QString& name, const char *propertyKey = nullptr, mitk::BaseProperty *property = nullptr );
 
 protected:
 
   void MirrorFibers();              ///< mirror bundle on the specified plane
   void ResampleSelectedBundlesSpline();   ///<
   void ResampleSelectedBundlesLinear();   ///<
   void DoImageColorCoding();        ///< color fibers by selected scalar image
   void DoWeightColorCoding();        ///< color fibers by their respective weights
   void DoCurvatureColorCoding();    ///< color fibers by curvature
   void CompressSelectedBundles();   ///< remove points below certain error threshold
   void WeightFibers();
+  void ApplyWeightThreshold();
 
   void RemoveWithMask(bool removeInside);
   void RemoveDir();
   void ApplyCurvatureThreshold();   ///< remove/split fibers with a too high curvature threshold
   void PruneBundle();               ///< remove too short/too long fibers
 
   void ExtractWithMask(bool onlyEnds, bool invert);
   void ExtractWithPlanarFigure(bool interactive=false);
 
   void OnEndInteraction();
 
   /// \brief called by QmitkAbstractView when DataManager's selection has changed
   virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList<mitk::DataNode::Pointer>& nodes) override;
 
   Ui::QmitkFiberProcessingViewControls* m_Controls;
 
   /** Connection from VTK to ITK */
   template <typename VTK_Exporter, typename ITK_Importer>
       void ConnectPipelines(VTK_Exporter* exporter, ITK_Importer importer)
   {
     importer->SetUpdateInformationCallback(exporter->GetUpdateInformationCallback());
 
     importer->SetPipelineModifiedCallback(exporter->GetPipelineModifiedCallback());
     importer->SetWholeExtentCallback(exporter->GetWholeExtentCallback());
     importer->SetSpacingCallback(exporter->GetSpacingCallback());
     importer->SetOriginCallback(exporter->GetOriginCallback());
     importer->SetScalarTypeCallback(exporter->GetScalarTypeCallback());
 
     importer->SetNumberOfComponentsCallback(exporter->GetNumberOfComponentsCallback());
 
     importer->SetPropagateUpdateExtentCallback(exporter->GetPropagateUpdateExtentCallback());
     importer->SetUpdateDataCallback(exporter->GetUpdateDataCallback());
     importer->SetDataExtentCallback(exporter->GetDataExtentCallback());
     importer->SetBufferPointerCallback(exporter->GetBufferPointerCallback());
     importer->SetCallbackUserData(exporter->GetCallbackUserData());
   }
 
   template <typename ITK_Exporter, typename VTK_Importer>
       void ConnectPipelines(ITK_Exporter exporter, VTK_Importer* importer)
   {
     importer->SetUpdateInformationCallback(exporter->GetUpdateInformationCallback());
 
     importer->SetPipelineModifiedCallback(exporter->GetPipelineModifiedCallback());
     importer->SetWholeExtentCallback(exporter->GetWholeExtentCallback());
     importer->SetSpacingCallback(exporter->GetSpacingCallback());
     importer->SetOriginCallback(exporter->GetOriginCallback());
     importer->SetScalarTypeCallback(exporter->GetScalarTypeCallback());
 
     importer->SetNumberOfComponentsCallback(exporter->GetNumberOfComponentsCallback());
 
     importer->SetPropagateUpdateExtentCallback(exporter->GetPropagateUpdateExtentCallback());
     importer->SetUpdateDataCallback(exporter->GetUpdateDataCallback());
     importer->SetDataExtentCallback(exporter->GetDataExtentCallback());
     importer->SetBufferPointerCallback(exporter->GetBufferPointerCallback());
     importer->SetCallbackUserData(exporter->GetCallbackUserData());
   }
 
   template < typename TPixel, unsigned int VImageDimension >
       void InternalCalculateMaskFromPlanarFigure(
           itk::Image< TPixel, VImageDimension > *image, unsigned int axis, std::string nodeName );
 
   template < typename TPixel, unsigned int VImageDimension >
       void InternalReorientImagePlane(
         const itk::Image< TPixel, VImageDimension > *image, mitk::BaseGeometry* planegeo3D, int additionalIndex );
 
   int m_CircleCounter;                                      ///< used for data node naming
   int m_PolygonCounter;                                     ///< used for data node naming
   std::vector<mitk::DataNode::Pointer>  m_SelectedFB;       ///< selected fiber bundle nodes
   std::vector<mitk::DataNode::Pointer>  m_SelectedPF;       ///< selected planar figure nodes
   std::vector<mitk::Surface::Pointer>   m_SelectedSurfaces;
   mitk::Image::Pointer                  m_SelectedImage;
   mitk::Image::Pointer                  m_InternalImage;
   mitk::PlanarFigure::Pointer           m_PlanarFigure;
   itkUCharImageType::Pointer            m_InternalImageMask3D;
   itkUCharImageType::Pointer            m_PlanarFigureImage;
   float                                 m_UpsamplingFactor; ///< upsampling factor for all image generations
   mitk::DataNode::Pointer               m_MaskImageNode;
 
   unsigned int                          m_StartInteractionObserverTag;
   unsigned int                          m_EndInteractionObserverTag;
   mitk::DataNode::Pointer               m_InteractiveNode;
 
   void AddCompositeToDatastorage(mitk::DataNode::Pointer pfc, std::vector<mitk::DataNode::Pointer> children, mitk::DataNode::Pointer parentNode=nullptr);
   void debugPFComposition(mitk::PlanarFigureComposite::Pointer , int );
   void WritePfToImage(mitk::DataNode::Pointer node, mitk::Image* image);
   mitk::DataNode::Pointer GenerateTractDensityImage(mitk::FiberBundle::Pointer fib, bool binary, bool absolute);
   mitk::DataNode::Pointer GenerateColorHeatmap(mitk::FiberBundle::Pointer fib);
   mitk::DataNode::Pointer GenerateFiberEndingsImage(mitk::FiberBundle::Pointer fib);
   mitk::DataNode::Pointer GenerateFiberEndingsPointSet(mitk::FiberBundle::Pointer fib);
 
   void NodeAdded( const mitk::DataNode* node ) override;
   void NodeRemoved(const mitk::DataNode* node) override;
   void RemoveObservers();
   void AddObservers();
 };
 
 
 
 #endif // _QMITKFIBERTRACKINGVIEW_H_INCLUDED
 
diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberProcessingViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberProcessingViewControls.ui
index d49bc8afea..3df18fd8fc 100644
--- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberProcessingViewControls.ui
+++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberProcessingViewControls.ui
@@ -1,1450 +1,1502 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <ui version="4.0">
  <class>QmitkFiberProcessingViewControls</class>
  <widget class="QWidget" name="QmitkFiberProcessingViewControls">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>385</width>
-    <height>564</height>
+    <height>684</height>
    </rect>
   </property>
   <property name="windowTitle">
    <string>Form</string>
   </property>
   <layout class="QGridLayout" name="gridLayout_3">
    <item row="1" column="0">
     <widget class="QToolBox" name="toolBoxx">
      <property name="currentIndex">
       <number>0</number>
      </property>
      <property name="tabSpacing">
       <number>5</number>
      </property>
      <widget class="QWidget" name="page">
       <property name="geometry">
        <rect>
         <x>0</x>
         <y>0</y>
-        <width>353</width>
+        <width>367</width>
         <height>382</height>
        </rect>
       </property>
       <attribute name="label">
        <string>Fiber Extraction</string>
       </attribute>
       <attribute name="toolTip">
        <string>Extract a fiber subset from the selected fiber bundle using manually placed planar figures as waypoints or binary regions of interest.</string>
       </attribute>
       <layout class="QGridLayout" name="gridLayout_14">
        <item row="5" column="0">
         <widget class="QCommandLinkButton" name="m_ExtractFibersButton">
          <property name="enabled">
           <bool>false</bool>
          </property>
          <property name="sizePolicy">
           <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
            <horstretch>0</horstretch>
            <verstretch>0</verstretch>
           </sizepolicy>
          </property>
          <property name="maximumSize">
           <size>
            <width>200</width>
            <height>16777215</height>
           </size>
          </property>
          <property name="font">
           <font>
            <pointsize>11</pointsize>
           </font>
          </property>
          <property name="toolTip">
           <string>Extract fibers passing through selected ROI or composite ROI. Select ROI and fiber bundle to execute.</string>
          </property>
          <property name="text">
           <string>Extract</string>
          </property>
         </widget>
        </item>
        <item row="6" column="0">
         <spacer name="verticalSpacer_5">
          <property name="orientation">
           <enum>Qt::Vertical</enum>
          </property>
          <property name="sizeHint" stdset="0">
           <size>
            <width>20</width>
            <height>40</height>
           </size>
          </property>
         </spacer>
        </item>
        <item row="3" column="0">
         <widget class="QFrame" name="m_ExtactionFramePF">
          <property name="frameShape">
           <enum>QFrame::NoFrame</enum>
          </property>
          <property name="frameShadow">
           <enum>QFrame::Raised</enum>
          </property>
          <layout class="QGridLayout" name="gridLayout_8">
           <property name="leftMargin">
            <number>9</number>
           </property>
           <property name="topMargin">
            <number>9</number>
           </property>
           <property name="rightMargin">
            <number>9</number>
           </property>
           <property name="bottomMargin">
            <number>9</number>
           </property>
           <property name="spacing">
            <number>0</number>
           </property>
           <item row="1" column="0">
            <widget class="QFrame" name="m_PlanarFigureButtonsFrame_2">
             <property name="sizePolicy">
              <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
               <horstretch>0</horstretch>
               <verstretch>0</verstretch>
              </sizepolicy>
             </property>
             <property name="minimumSize">
              <size>
               <width>200</width>
               <height>0</height>
              </size>
             </property>
             <property name="maximumSize">
              <size>
               <width>16777215</width>
               <height>60</height>
              </size>
             </property>
             <property name="frameShape">
              <enum>QFrame::NoFrame</enum>
             </property>
             <property name="frameShadow">
              <enum>QFrame::Raised</enum>
             </property>
             <layout class="QGridLayout" name="gridLayout_5">
              <property name="leftMargin">
               <number>0</number>
              </property>
              <property name="topMargin">
               <number>0</number>
              </property>
              <property name="rightMargin">
               <number>0</number>
              </property>
              <property name="bottomMargin">
               <number>0</number>
              </property>
              <item row="0" column="1">
               <widget class="QCommandLinkButton" name="PFCompoORButton">
                <property name="enabled">
                 <bool>false</bool>
                </property>
                <property name="maximumSize">
                 <size>
                  <width>60</width>
                  <height>16777215</height>
                 </size>
                </property>
                <property name="toolTip">
                 <string>Create OR composition with selected ROIs.</string>
                </property>
                <property name="text">
                 <string>OR</string>
                </property>
               </widget>
              </item>
              <item row="0" column="3">
               <spacer name="horizontalSpacer_3">
                <property name="orientation">
                 <enum>Qt::Horizontal</enum>
                </property>
                <property name="sizeHint" stdset="0">
                 <size>
                  <width>40</width>
                  <height>20</height>
                 </size>
                </property>
               </spacer>
              </item>
              <item row="0" column="2">
               <widget class="QCommandLinkButton" name="PFCompoNOTButton">
                <property name="enabled">
                 <bool>false</bool>
                </property>
                <property name="maximumSize">
                 <size>
                  <width>60</width>
                  <height>16777215</height>
                 </size>
                </property>
                <property name="toolTip">
                 <string>Create NOT composition from selected ROI.</string>
                </property>
                <property name="text">
                 <string>NOT</string>
                </property>
               </widget>
              </item>
              <item row="0" column="0">
               <widget class="QCommandLinkButton" name="PFCompoANDButton">
                <property name="enabled">
                 <bool>false</bool>
                </property>
                <property name="maximumSize">
                 <size>
                  <width>60</width>
                  <height>16777215</height>
                 </size>
                </property>
                <property name="toolTip">
                 <string>Create AND composition with selected ROIs.</string>
                </property>
                <property name="text">
                 <string>AND</string>
                </property>
               </widget>
              </item>
             </layout>
            </widget>
           </item>
           <item row="0" column="0">
            <widget class="QFrame" name="m_PlanarFigureButtonsFrame">
             <property name="sizePolicy">
              <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
               <horstretch>0</horstretch>
               <verstretch>0</verstretch>
              </sizepolicy>
             </property>
             <property name="minimumSize">
              <size>
               <width>200</width>
               <height>0</height>
              </size>
             </property>
             <property name="maximumSize">
              <size>
               <width>16777215</width>
               <height>60</height>
              </size>
             </property>
             <property name="frameShape">
              <enum>QFrame::NoFrame</enum>
             </property>
             <property name="frameShadow">
              <enum>QFrame::Raised</enum>
             </property>
             <layout class="QGridLayout" name="gridLayout">
              <property name="leftMargin">
               <number>0</number>
              </property>
              <property name="topMargin">
               <number>0</number>
              </property>
              <property name="rightMargin">
               <number>0</number>
              </property>
              <property name="bottomMargin">
               <number>0</number>
              </property>
              <item row="0" column="0">
               <widget class="QPushButton" name="m_CircleButton">
                <property name="maximumSize">
                 <size>
                  <width>30</width>
                  <height>30</height>
                 </size>
                </property>
                <property name="toolTip">
                 <string>Draw circular ROI. Select reference fiber bundle to execute.</string>
                </property>
                <property name="text">
                 <string/>
                </property>
                <property name="icon">
                 <iconset resource="../../../org.mitk.gui.qt.diffusionimaging.fiberfox/resources/QmitkDiffusionImaging.qrc">
                  <normaloff>:/QmitkDiffusionImaging/circle.png</normaloff>:/QmitkDiffusionImaging/circle.png</iconset>
                </property>
                <property name="iconSize">
                 <size>
                  <width>32</width>
                  <height>32</height>
                 </size>
                </property>
                <property name="checkable">
                 <bool>false</bool>
                </property>
                <property name="flat">
                 <bool>true</bool>
                </property>
               </widget>
              </item>
              <item row="0" column="2">
               <spacer name="horizontalSpacer">
                <property name="orientation">
                 <enum>Qt::Horizontal</enum>
                </property>
                <property name="sizeHint" stdset="0">
                 <size>
                  <width>40</width>
                  <height>20</height>
                 </size>
                </property>
               </spacer>
              </item>
              <item row="0" column="1">
               <widget class="QPushButton" name="m_PolygonButton">
                <property name="maximumSize">
                 <size>
                  <width>30</width>
                  <height>30</height>
                 </size>
                </property>
                <property name="toolTip">
                 <string>Draw polygonal ROI. Select reference fiber bundle to execute.</string>
                </property>
                <property name="text">
                 <string/>
                </property>
                <property name="icon">
                 <iconset resource="../../resources/QmitkDiffusionImaging.qrc">
                  <normaloff>:/QmitkDiffusionImaging/polygon.png</normaloff>:/QmitkDiffusionImaging/polygon.png</iconset>
                </property>
                <property name="iconSize">
                 <size>
                  <width>32</width>
                  <height>32</height>
                 </size>
                </property>
                <property name="checkable">
                 <bool>true</bool>
                </property>
                <property name="flat">
                 <bool>true</bool>
                </property>
               </widget>
              </item>
             </layout>
            </widget>
           </item>
           <item row="2" column="0">
            <widget class="QCommandLinkButton" name="m_GenerateRoiImage">
             <property name="enabled">
              <bool>false</bool>
             </property>
             <property name="sizePolicy">
              <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
               <horstretch>0</horstretch>
               <verstretch>0</verstretch>
              </sizepolicy>
             </property>
             <property name="maximumSize">
              <size>
               <width>16777215</width>
               <height>16777215</height>
              </size>
             </property>
             <property name="font">
              <font>
               <pointsize>11</pointsize>
              </font>
             </property>
             <property name="toolTip">
              <string>Generate a binary image containing all selected ROIs. Select at least one ROI (planar figure) and a reference fiber bundle or image.</string>
             </property>
             <property name="text">
              <string>Generate ROI Image</string>
             </property>
            </widget>
           </item>
           <item row="3" column="0">
            <widget class="QCheckBox" name="m_InteractiveBox">
             <property name="text">
              <string>Interactive Extraction</string>
             </property>
            </widget>
           </item>
          </layout>
         </widget>
        </item>
        <item row="0" column="0">
         <widget class="QComboBox" name="m_ExtractionMethodBox">
          <property name="sizePolicy">
           <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
            <horstretch>0</horstretch>
            <verstretch>0</verstretch>
           </sizepolicy>
          </property>
          <item>
           <property name="text">
            <string>Extract using planar figures</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>Extract using binary ROI image</string>
           </property>
          </item>
         </widget>
        </item>
        <item row="4" column="0">
         <widget class="QFrame" name="m_MaskExtractionFrame">
          <property name="frameShape">
           <enum>QFrame::NoFrame</enum>
          </property>
          <property name="frameShadow">
           <enum>QFrame::Raised</enum>
          </property>
          <layout class="QGridLayout" name="gridLayout_19">
           <property name="leftMargin">
            <number>0</number>
           </property>
           <property name="topMargin">
            <number>0</number>
           </property>
           <property name="rightMargin">
            <number>0</number>
           </property>
           <property name="bottomMargin">
            <number>0</number>
           </property>
           <item row="3" column="0">
            <widget class="QCheckBox" name="m_BothEnds">
             <property name="text">
              <string>Both ends</string>
             </property>
             <property name="checked">
              <bool>true</bool>
             </property>
            </widget>
           </item>
           <item row="2" column="2">
            <widget class="QDoubleSpinBox" name="m_FiberExtractionFractionBox">
             <property name="maximum">
              <double>1.000000000000000</double>
             </property>
             <property name="singleStep">
              <double>0.100000000000000</double>
             </property>
            </widget>
           </item>
           <item row="0" column="0">
            <widget class="QLabel" name="label_16">
             <property name="text">
              <string>Extract fibers:</string>
             </property>
            </widget>
           </item>
           <item row="0" column="2">
            <widget class="QComboBox" name="m_ExtractionBoxMask">
             <property name="sizePolicy">
              <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
               <horstretch>0</horstretch>
               <verstretch>0</verstretch>
              </sizepolicy>
             </property>
             <item>
              <property name="text">
               <string>Ending in mask</string>
              </property>
             </item>
             <item>
              <property name="text">
               <string>Not ending in mask</string>
              </property>
             </item>
             <item>
              <property name="text">
               <string>Passing mask</string>
              </property>
             </item>
             <item>
              <property name="text">
               <string>Not passing mask</string>
              </property>
             </item>
            </widget>
           </item>
           <item row="2" column="0">
            <widget class="QLabel" name="label_17">
             <property name="text">
              <string>Min. overlap:</string>
             </property>
            </widget>
           </item>
          </layout>
         </widget>
        </item>
       </layout>
      </widget>
      <widget class="QWidget" name="page_3">
       <property name="geometry">
        <rect>
         <x>0</x>
         <y>0</y>
-        <width>353</width>
-        <height>371</height>
+        <width>367</width>
+        <height>408</height>
        </rect>
       </property>
       <attribute name="label">
        <string>Fiber Removal</string>
       </attribute>
       <attribute name="toolTip">
        <string>Remove fibers that satisfy certain criteria from the selected bundle.</string>
       </attribute>
       <layout class="QGridLayout" name="gridLayout_4">
-       <item row="0" column="0">
-        <widget class="QComboBox" name="m_RemovalMethodBox">
-         <property name="sizePolicy">
-          <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
-           <horstretch>0</horstretch>
-           <verstretch>0</verstretch>
-          </sizepolicy>
-         </property>
-         <item>
-          <property name="text">
-           <string>Remove fibers in direction</string>
-          </property>
-         </item>
-         <item>
-          <property name="text">
-           <string>Remove fibers by length</string>
-          </property>
-         </item>
-         <item>
-          <property name="text">
-           <string>Remove fibers by curvature</string>
-          </property>
-         </item>
-         <item>
-          <property name="text">
-           <string>Remove fiber parts outside mask</string>
-          </property>
-         </item>
-         <item>
-          <property name="text">
-           <string>Remove fiber parts inside mask</string>
-          </property>
-         </item>
-        </widget>
-       </item>
-       <item row="2" column="0">
-        <widget class="QFrame" name="m_RemoveLengthFrame">
+       <item row="3" column="0">
+        <widget class="QFrame" name="m_RemoveCurvatureFrame">
          <property name="frameShape">
           <enum>QFrame::NoFrame</enum>
          </property>
          <property name="frameShadow">
           <enum>QFrame::Raised</enum>
          </property>
-         <layout class="QGridLayout" name="gridLayout_6">
+         <layout class="QGridLayout" name="gridLayout_11">
           <property name="leftMargin">
            <number>0</number>
           </property>
           <property name="topMargin">
            <number>0</number>
           </property>
           <property name="rightMargin">
            <number>0</number>
           </property>
           <property name="bottomMargin">
            <number>0</number>
           </property>
-          <item row="0" column="2">
-           <spacer name="horizontalSpacer_4">
-            <property name="orientation">
-             <enum>Qt::Horizontal</enum>
-            </property>
-            <property name="sizeHint" stdset="0">
-             <size>
-              <width>40</width>
-              <height>20</height>
-             </size>
-            </property>
-           </spacer>
-          </item>
-          <item row="0" column="1">
-           <widget class="QSpinBox" name="m_PruneFibersMinBox">
+          <item row="2" column="2">
+           <widget class="QCheckBox" name="m_RemoveCurvedFibersBox">
             <property name="toolTip">
-             <string>Minimum fiber length in mm</string>
-            </property>
-            <property name="minimum">
-             <number>0</number>
-            </property>
-            <property name="maximum">
-             <number>999999999</number>
-            </property>
-            <property name="value">
-             <number>20</number>
+             <string>If unchecked, the fiber exceeding the threshold will be split in two instead of removed.</string>
             </property>
-           </widget>
-          </item>
-          <item row="1" column="0">
-           <widget class="QLabel" name="label_9">
             <property name="text">
-             <string>Max. Length:</string>
+             <string>Remove Fiber</string>
             </property>
-           </widget>
-          </item>
-          <item row="0" column="0">
-           <widget class="QLabel" name="label_7">
-            <property name="text">
-             <string>Min. Length:</string>
+            <property name="checked">
+             <bool>false</bool>
             </property>
            </widget>
           </item>
-          <item row="1" column="1">
-           <widget class="QSpinBox" name="m_PruneFibersMaxBox">
-            <property name="toolTip">
-             <string>Maximum fiber length in mm</string>
-            </property>
-            <property name="minimum">
-             <number>0</number>
-            </property>
-            <property name="maximum">
-             <number>999999999</number>
+          <item row="1" column="2">
+           <widget class="QFrame" name="frame">
+            <property name="frameShape">
+             <enum>QFrame::NoFrame</enum>
             </property>
-            <property name="value">
-             <number>300</number>
+            <property name="frameShadow">
+             <enum>QFrame::Raised</enum>
             </property>
+            <layout class="QGridLayout" name="gridLayout_12">
+             <property name="leftMargin">
+              <number>0</number>
+             </property>
+             <property name="topMargin">
+              <number>0</number>
+             </property>
+             <property name="rightMargin">
+              <number>0</number>
+             </property>
+             <property name="bottomMargin">
+              <number>0</number>
+             </property>
+             <property name="verticalSpacing">
+              <number>0</number>
+             </property>
+             <item row="0" column="0">
+              <widget class="QLabel" name="label_8">
+               <property name="text">
+                <string>Max. Angular Deviation:</string>
+               </property>
+              </widget>
+             </item>
+             <item row="0" column="2">
+              <spacer name="horizontalSpacer_5">
+               <property name="orientation">
+                <enum>Qt::Horizontal</enum>
+               </property>
+               <property name="sizeHint" stdset="0">
+                <size>
+                 <width>40</width>
+                 <height>20</height>
+                </size>
+               </property>
+              </spacer>
+             </item>
+             <item row="0" column="1">
+              <widget class="QDoubleSpinBox" name="m_CurvSpinBox">
+               <property name="toolTip">
+                <string>Maximum angular deviation in degree</string>
+               </property>
+               <property name="maximum">
+                <double>180.000000000000000</double>
+               </property>
+               <property name="singleStep">
+                <double>0.100000000000000</double>
+               </property>
+               <property name="value">
+                <double>30.000000000000000</double>
+               </property>
+              </widget>
+             </item>
+             <item row="1" column="0">
+              <widget class="QLabel" name="label_14">
+               <property name="text">
+                <string>Distance:</string>
+               </property>
+              </widget>
+             </item>
+             <item row="1" column="1">
+              <widget class="QDoubleSpinBox" name="m_CurvDistanceSpinBox">
+               <property name="toolTip">
+                <string>Distance in mm</string>
+               </property>
+               <property name="decimals">
+                <number>1</number>
+               </property>
+               <property name="maximum">
+                <double>999.000000000000000</double>
+               </property>
+               <property name="singleStep">
+                <double>1.000000000000000</double>
+               </property>
+               <property name="value">
+                <double>10.000000000000000</double>
+               </property>
+              </widget>
+             </item>
+            </layout>
            </widget>
           </item>
          </layout>
         </widget>
        </item>
        <item row="1" column="0">
         <widget class="QFrame" name="m_RemoveDirectionFrame">
          <property name="frameShape">
           <enum>QFrame::NoFrame</enum>
          </property>
          <property name="frameShadow">
           <enum>QFrame::Raised</enum>
          </property>
          <layout class="QGridLayout" name="gridLayout_2">
           <property name="leftMargin">
            <number>0</number>
           </property>
           <property name="topMargin">
            <number>0</number>
           </property>
           <property name="rightMargin">
            <number>0</number>
           </property>
           <property name="bottomMargin">
            <number>0</number>
           </property>
           <property name="horizontalSpacing">
            <number>0</number>
           </property>
           <item row="0" column="0">
            <widget class="QLabel" name="label">
             <property name="text">
              <string>X:</string>
             </property>
            </widget>
           </item>
           <item row="1" column="0">
            <widget class="QLabel" name="label_3">
             <property name="text">
              <string>Y:</string>
             </property>
            </widget>
           </item>
           <item row="0" column="1">
            <widget class="QDoubleSpinBox" name="m_ExtractDirX"/>
           </item>
           <item row="1" column="1">
            <widget class="QDoubleSpinBox" name="m_ExtractDirY"/>
           </item>
           <item row="2" column="0">
            <widget class="QLabel" name="label_4">
             <property name="text">
              <string>Z:</string>
             </property>
            </widget>
           </item>
           <item row="2" column="1">
            <widget class="QDoubleSpinBox" name="m_ExtractDirZ"/>
           </item>
           <item row="3" column="0">
            <widget class="QLabel" name="label_5">
             <property name="text">
              <string>Angle:</string>
             </property>
            </widget>
           </item>
           <item row="3" column="1">
            <widget class="QDoubleSpinBox" name="m_ExtractAngle">
             <property name="toolTip">
              <string>Angular deviation threshold in degree</string>
             </property>
             <property name="decimals">
              <number>1</number>
             </property>
             <property name="maximum">
              <double>90.000000000000000</double>
             </property>
             <property name="singleStep">
              <double>1.000000000000000</double>
             </property>
             <property name="value">
              <double>25.000000000000000</double>
             </property>
            </widget>
           </item>
          </layout>
         </widget>
        </item>
-       <item row="3" column="0">
-        <widget class="QFrame" name="m_RemoveCurvatureFrame">
+       <item row="2" column="0">
+        <widget class="QFrame" name="m_RemoveLengthFrame">
          <property name="frameShape">
           <enum>QFrame::NoFrame</enum>
          </property>
          <property name="frameShadow">
           <enum>QFrame::Raised</enum>
          </property>
-         <layout class="QGridLayout" name="gridLayout_11">
+         <layout class="QGridLayout" name="gridLayout_6">
           <property name="leftMargin">
            <number>0</number>
           </property>
           <property name="topMargin">
            <number>0</number>
           </property>
           <property name="rightMargin">
            <number>0</number>
           </property>
           <property name="bottomMargin">
            <number>0</number>
           </property>
-          <item row="2" column="2">
-           <widget class="QCheckBox" name="m_RemoveCurvedFibersBox">
+          <item row="0" column="2">
+           <spacer name="horizontalSpacer_4">
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+            <property name="sizeHint" stdset="0">
+             <size>
+              <width>40</width>
+              <height>20</height>
+             </size>
+            </property>
+           </spacer>
+          </item>
+          <item row="0" column="1">
+           <widget class="QSpinBox" name="m_PruneFibersMinBox">
             <property name="toolTip">
-             <string>If unchecked, the fiber exceeding the threshold will be split in two instead of removed.</string>
+             <string>Minimum fiber length in mm</string>
+            </property>
+            <property name="minimum">
+             <number>0</number>
+            </property>
+            <property name="maximum">
+             <number>999999999</number>
             </property>
+            <property name="value">
+             <number>20</number>
+            </property>
+           </widget>
+          </item>
+          <item row="1" column="0">
+           <widget class="QLabel" name="label_9">
             <property name="text">
-             <string>Remove Fiber</string>
+             <string>Max. Length:</string>
             </property>
-            <property name="checked">
-             <bool>false</bool>
+           </widget>
+          </item>
+          <item row="0" column="0">
+           <widget class="QLabel" name="label_7">
+            <property name="text">
+             <string>Min. Length:</string>
             </property>
            </widget>
           </item>
-          <item row="1" column="2">
-           <widget class="QFrame" name="frame">
-            <property name="frameShape">
-             <enum>QFrame::NoFrame</enum>
+          <item row="1" column="1">
+           <widget class="QSpinBox" name="m_PruneFibersMaxBox">
+            <property name="toolTip">
+             <string>Maximum fiber length in mm</string>
             </property>
-            <property name="frameShadow">
-             <enum>QFrame::Raised</enum>
+            <property name="minimum">
+             <number>0</number>
+            </property>
+            <property name="maximum">
+             <number>999999999</number>
+            </property>
+            <property name="value">
+             <number>300</number>
             </property>
-            <layout class="QGridLayout" name="gridLayout_12">
-             <property name="leftMargin">
-              <number>0</number>
-             </property>
-             <property name="topMargin">
-              <number>0</number>
-             </property>
-             <property name="rightMargin">
-              <number>0</number>
-             </property>
-             <property name="bottomMargin">
-              <number>0</number>
-             </property>
-             <property name="verticalSpacing">
-              <number>0</number>
-             </property>
-             <item row="0" column="0">
-              <widget class="QLabel" name="label_8">
-               <property name="text">
-                <string>Max. Angular Deviation:</string>
-               </property>
-              </widget>
-             </item>
-             <item row="0" column="2">
-              <spacer name="horizontalSpacer_5">
-               <property name="orientation">
-                <enum>Qt::Horizontal</enum>
-               </property>
-               <property name="sizeHint" stdset="0">
-                <size>
-                 <width>40</width>
-                 <height>20</height>
-                </size>
-               </property>
-              </spacer>
-             </item>
-             <item row="0" column="1">
-              <widget class="QDoubleSpinBox" name="m_CurvSpinBox">
-               <property name="toolTip">
-                <string>Maximum angular deviation in degree</string>
-               </property>
-               <property name="maximum">
-                <double>180.000000000000000</double>
-               </property>
-               <property name="singleStep">
-                <double>0.100000000000000</double>
-               </property>
-               <property name="value">
-                <double>30.000000000000000</double>
-               </property>
-              </widget>
-             </item>
-             <item row="1" column="0">
-              <widget class="QLabel" name="label_14">
-               <property name="text">
-                <string>Distance:</string>
-               </property>
-              </widget>
-             </item>
-             <item row="1" column="1">
-              <widget class="QDoubleSpinBox" name="m_CurvDistanceSpinBox">
-               <property name="toolTip">
-                <string>Distance in mm</string>
-               </property>
-               <property name="decimals">
-                <number>1</number>
-               </property>
-               <property name="maximum">
-                <double>999.000000000000000</double>
-               </property>
-               <property name="singleStep">
-                <double>1.000000000000000</double>
-               </property>
-               <property name="value">
-                <double>10.000000000000000</double>
-               </property>
-              </widget>
-             </item>
-            </layout>
            </widget>
           </item>
          </layout>
         </widget>
        </item>
-       <item row="4" column="0">
+       <item row="5" column="0">
         <widget class="QCommandLinkButton" name="m_RemoveButton">
          <property name="enabled">
           <bool>false</bool>
          </property>
          <property name="sizePolicy">
           <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
            <horstretch>0</horstretch>
            <verstretch>0</verstretch>
           </sizepolicy>
          </property>
          <property name="maximumSize">
           <size>
            <width>200</width>
            <height>16777215</height>
           </size>
          </property>
          <property name="font">
           <font>
            <pointsize>11</pointsize>
           </font>
          </property>
          <property name="toolTip">
           <string/>
          </property>
          <property name="text">
           <string>Remove</string>
          </property>
         </widget>
        </item>
-       <item row="5" column="0">
+       <item row="6" column="0">
         <spacer name="verticalSpacer_4">
          <property name="orientation">
           <enum>Qt::Vertical</enum>
          </property>
          <property name="sizeHint" stdset="0">
           <size>
            <width>20</width>
            <height>40</height>
           </size>
          </property>
         </spacer>
        </item>
+       <item row="0" column="0">
+        <widget class="QComboBox" name="m_RemovalMethodBox">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <item>
+          <property name="text">
+           <string>Remove fibers in direction</string>
+          </property>
+         </item>
+         <item>
+          <property name="text">
+           <string>Remove fibers by length</string>
+          </property>
+         </item>
+         <item>
+          <property name="text">
+           <string>Remove fibers by curvature</string>
+          </property>
+         </item>
+         <item>
+          <property name="text">
+           <string>Remove fiber parts outside mask</string>
+          </property>
+         </item>
+         <item>
+          <property name="text">
+           <string>Remove fiber parts inside mask</string>
+          </property>
+         </item>
+         <item>
+          <property name="text">
+           <string>Remove fibers by weight</string>
+          </property>
+         </item>
+        </widget>
+       </item>
+       <item row="4" column="0">
+        <widget class="QFrame" name="m_RemoveByWeightFrame">
+         <property name="frameShape">
+          <enum>QFrame::NoFrame</enum>
+         </property>
+         <property name="frameShadow">
+          <enum>QFrame::Raised</enum>
+         </property>
+         <layout class="QGridLayout" name="gridLayout_20">
+          <property name="leftMargin">
+           <number>0</number>
+          </property>
+          <property name="topMargin">
+           <number>0</number>
+          </property>
+          <property name="rightMargin">
+           <number>0</number>
+          </property>
+          <property name="bottomMargin">
+           <number>0</number>
+          </property>
+          <property name="spacing">
+           <number>0</number>
+          </property>
+          <item row="1" column="0">
+           <widget class="QLabel" name="label_18">
+            <property name="text">
+             <string>Weight threshold:</string>
+            </property>
+           </widget>
+          </item>
+          <item row="1" column="1">
+           <widget class="QDoubleSpinBox" name="m_WeightThresholdBox">
+            <property name="toolTip">
+             <string>Only fibers with weight larger than this threshold are kept.</string>
+            </property>
+            <property name="decimals">
+             <number>5</number>
+            </property>
+            <property name="singleStep">
+             <double>0.100000000000000</double>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+       </item>
       </layout>
      </widget>
      <widget class="QWidget" name="page_4">
       <property name="geometry">
        <rect>
         <x>0</x>
         <y>0</y>
-        <width>353</width>
-        <height>364</height>
+        <width>367</width>
+        <height>408</height>
        </rect>
       </property>
       <attribute name="label">
        <string>Bundle Modification</string>
       </attribute>
       <attribute name="toolTip">
        <string>Modify the selected bundle with operations such as fiber resampling, FA coloring, etc.</string>
       </attribute>
       <layout class="QGridLayout" name="gridLayout_10">
        <item row="2" column="0">
         <widget class="QFrame" name="m_CompressFibersFrame">
          <property name="frameShape">
           <enum>QFrame::NoFrame</enum>
          </property>
          <property name="frameShadow">
           <enum>QFrame::Raised</enum>
          </property>
          <layout class="QGridLayout" name="gridLayout_15">
           <property name="leftMargin">
            <number>0</number>
           </property>
           <property name="topMargin">
            <number>0</number>
           </property>
           <property name="rightMargin">
            <number>0</number>
           </property>
           <property name="bottomMargin">
            <number>0</number>
           </property>
           <property name="spacing">
            <number>0</number>
           </property>
           <item row="0" column="0">
            <widget class="QLabel" name="label_10">
             <property name="text">
              <string>Error threshold in mm:</string>
             </property>
            </widget>
           </item>
           <item row="1" column="0">
            <widget class="QDoubleSpinBox" name="m_ErrorThresholdBox">
             <property name="maximum">
              <double>999999999.000000000000000</double>
             </property>
             <property name="singleStep">
              <double>0.100000000000000</double>
             </property>
             <property name="value">
              <double>0.100000000000000</double>
             </property>
            </widget>
           </item>
          </layout>
         </widget>
        </item>
        <item row="4" column="0">
         <widget class="QFrame" name="m_MirrorFibersFrame">
          <property name="frameShape">
           <enum>QFrame::NoFrame</enum>
          </property>
          <property name="frameShadow">
           <enum>QFrame::Raised</enum>
          </property>
          <layout class="QGridLayout" name="gridLayout_17">
           <property name="leftMargin">
            <number>0</number>
           </property>
           <property name="topMargin">
            <number>0</number>
           </property>
           <property name="rightMargin">
            <number>0</number>
           </property>
           <property name="bottomMargin">
            <number>0</number>
           </property>
           <property name="spacing">
            <number>0</number>
           </property>
           <item row="1" column="0">
            <widget class="QComboBox" name="m_MirrorFibersBox">
             <item>
              <property name="text">
               <string>Sagittal</string>
              </property>
             </item>
             <item>
              <property name="text">
               <string>Coronal</string>
              </property>
             </item>
             <item>
              <property name="text">
               <string>Axial</string>
              </property>
             </item>
            </widget>
           </item>
           <item row="0" column="0">
            <widget class="QLabel" name="label_13">
             <property name="text">
              <string>Select direction:</string>
             </property>
            </widget>
           </item>
          </layout>
         </widget>
        </item>
        <item row="3" column="0">
         <widget class="QFrame" name="m_ColorFibersFrame">
          <property name="frameShape">
           <enum>QFrame::NoFrame</enum>
          </property>
          <property name="frameShadow">
           <enum>QFrame::Raised</enum>
          </property>
          <layout class="QGridLayout" name="gridLayout_16">
           <property name="leftMargin">
            <number>0</number>
           </property>
           <property name="topMargin">
            <number>0</number>
           </property>
           <property name="rightMargin">
            <number>0</number>
           </property>
           <property name="bottomMargin">
            <number>0</number>
           </property>
           <property name="spacing">
            <number>0</number>
           </property>
           <item row="1" column="0">
            <widget class="QCheckBox" name="m_FiberOpacityBox">
             <property name="toolTip">
              <string>If checked, the image values are not only used to color the fibers but are also used as opaxity values.</string>
             </property>
             <property name="text">
              <string>Values as opacity</string>
             </property>
             <property name="checked">
              <bool>false</bool>
             </property>
            </widget>
           </item>
           <item row="3" column="0">
            <widget class="QmitkDataStorageComboBox" name="m_ColorMapBox"/>
           </item>
           <item row="0" column="0">
            <widget class="QLabel" name="label_12">
             <property name="text">
              <string>Scalar map:</string>
             </property>
            </widget>
           </item>
           <item row="2" column="0">
            <widget class="QCheckBox" name="m_NormalizeColorValues">
             <property name="toolTip">
              <string>The values used to color the fibers are min-max normalized. If not checked, the values should be between 0 and 1. </string>
             </property>
             <property name="text">
              <string>Normalize values</string>
             </property>
             <property name="checked">
              <bool>true</bool>
             </property>
            </widget>
           </item>
          </layout>
         </widget>
        </item>
        <item row="0" column="0">
         <widget class="QComboBox" name="m_ModificationMethodBox">
          <property name="sizePolicy">
           <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
            <horstretch>0</horstretch>
            <verstretch>0</verstretch>
           </sizepolicy>
          </property>
          <item>
           <property name="text">
            <string>Resample fibers (spline)</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>Resample fibers (linear)</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>Compress fibers</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>Color fibers by scalar map (e.g. FA)</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>Mirror fibers</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>Weight bundle</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>Color fibers by curvature</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>Color fibers by fiber weights</string>
           </property>
          </item>
         </widget>
        </item>
        <item row="1" column="0">
         <widget class="QFrame" name="m_SmoothFibersFrame">
          <property name="frameShape">
           <enum>QFrame::NoFrame</enum>
          </property>
          <property name="frameShadow">
           <enum>QFrame::Raised</enum>
          </property>
          <layout class="QGridLayout" name="gridLayout_7">
           <property name="leftMargin">
            <number>0</number>
           </property>
           <property name="topMargin">
            <number>0</number>
           </property>
           <property name="rightMargin">
            <number>0</number>
           </property>
           <property name="bottomMargin">
            <number>0</number>
           </property>
           <property name="spacing">
            <number>0</number>
           </property>
           <item row="1" column="0">
            <widget class="QDoubleSpinBox" name="m_SmoothFibersBox">
             <property name="minimum">
              <double>0.010000000000000</double>
             </property>
             <property name="maximum">
              <double>999999999.000000000000000</double>
             </property>
             <property name="singleStep">
              <double>0.100000000000000</double>
             </property>
             <property name="value">
              <double>1.000000000000000</double>
             </property>
            </widget>
           </item>
           <item row="0" column="0">
            <widget class="QLabel" name="label_11">
             <property name="text">
              <string>Point distance in mm:</string>
             </property>
            </widget>
           </item>
          </layout>
         </widget>
        </item>
        <item row="7" column="0">
         <spacer name="verticalSpacer_3">
          <property name="orientation">
           <enum>Qt::Vertical</enum>
          </property>
          <property name="sizeHint" stdset="0">
           <size>
            <width>20</width>
            <height>40</height>
           </size>
          </property>
         </spacer>
        </item>
        <item row="6" column="0">
         <widget class="QCommandLinkButton" name="m_ModifyButton">
          <property name="enabled">
           <bool>false</bool>
          </property>
          <property name="sizePolicy">
           <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
            <horstretch>0</horstretch>
            <verstretch>0</verstretch>
           </sizepolicy>
          </property>
          <property name="maximumSize">
           <size>
            <width>200</width>
            <height>16777215</height>
           </size>
          </property>
          <property name="font">
           <font>
            <pointsize>11</pointsize>
           </font>
          </property>
          <property name="toolTip">
           <string/>
          </property>
          <property name="text">
           <string>Execute</string>
          </property>
         </widget>
        </item>
        <item row="5" column="0">
         <widget class="QFrame" name="m_BundleWeightFrame">
          <property name="frameShape">
           <enum>QFrame::NoFrame</enum>
          </property>
          <property name="frameShadow">
           <enum>QFrame::Raised</enum>
          </property>
          <layout class="QGridLayout" name="gridLayout_18">
           <property name="leftMargin">
            <number>0</number>
           </property>
           <property name="topMargin">
            <number>0</number>
           </property>
           <property name="rightMargin">
            <number>0</number>
           </property>
           <property name="bottomMargin">
            <number>0</number>
           </property>
           <property name="spacing">
            <number>0</number>
           </property>
           <item row="0" column="0">
            <widget class="QLabel" name="label_15">
             <property name="text">
              <string>Weight:</string>
             </property>
            </widget>
           </item>
           <item row="0" column="1">
            <widget class="QDoubleSpinBox" name="m_BundleWeightBox">
             <property name="decimals">
              <number>7</number>
             </property>
             <property name="maximum">
              <double>999999999.000000000000000</double>
             </property>
             <property name="singleStep">
              <double>0.100000000000000</double>
             </property>
             <property name="value">
              <double>1.000000000000000</double>
             </property>
            </widget>
           </item>
          </layout>
         </widget>
        </item>
       </layout>
      </widget>
      <widget class="QWidget" name="page_2">
       <property name="geometry">
        <rect>
         <x>0</x>
         <y>0</y>
         <width>367</width>
-        <height>152</height>
+        <height>165</height>
        </rect>
       </property>
       <attribute name="label">
        <string>Bundle Operations</string>
       </attribute>
       <attribute name="toolTip">
        <string>Join, subtract or copy bundles.</string>
       </attribute>
       <layout class="QGridLayout" name="gridLayout_13">
        <item row="0" column="0">
         <widget class="QCommandLinkButton" name="m_SubstractBundles">
          <property name="enabled">
           <bool>false</bool>
          </property>
          <property name="sizePolicy">
           <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
            <horstretch>0</horstretch>
            <verstretch>0</verstretch>
           </sizepolicy>
          </property>
          <property name="maximumSize">
           <size>
            <width>200</width>
            <height>16777215</height>
           </size>
          </property>
          <property name="font">
           <font>
            <pointsize>11</pointsize>
           </font>
          </property>
          <property name="toolTip">
           <string>Returns all fibers contained in bundle X that are not contained in bundle Y (not commutative!). Select at least two fiber bundles to execute.</string>
          </property>
          <property name="text">
           <string>Substract</string>
          </property>
         </widget>
        </item>
        <item row="2" column="0">
         <spacer name="verticalSpacer_2">
          <property name="orientation">
           <enum>Qt::Vertical</enum>
          </property>
          <property name="sizeHint" stdset="0">
           <size>
            <width>20</width>
            <height>40</height>
           </size>
          </property>
         </spacer>
        </item>
        <item row="0" column="2">
         <widget class="QCommandLinkButton" name="m_JoinBundles">
          <property name="enabled">
           <bool>false</bool>
          </property>
          <property name="sizePolicy">
           <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
            <horstretch>0</horstretch>
            <verstretch>0</verstretch>
           </sizepolicy>
          </property>
          <property name="maximumSize">
           <size>
            <width>200</width>
            <height>16777215</height>
           </size>
          </property>
          <property name="font">
           <font>
            <pointsize>11</pointsize>
           </font>
          </property>
          <property name="toolTip">
           <string>Merge selected fiber bundles. Select at least two fiber bundles to execute.</string>
          </property>
          <property name="text">
           <string>Join</string>
          </property>
         </widget>
        </item>
        <item row="1" column="0">
         <widget class="QCommandLinkButton" name="m_CopyBundle">
          <property name="enabled">
           <bool>false</bool>
          </property>
          <property name="sizePolicy">
           <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
            <horstretch>0</horstretch>
            <verstretch>0</verstretch>
           </sizepolicy>
          </property>
          <property name="maximumSize">
           <size>
            <width>200</width>
            <height>16777215</height>
           </size>
          </property>
          <property name="font">
           <font>
            <pointsize>11</pointsize>
           </font>
          </property>
          <property name="toolTip">
           <string>Merge selected fiber bundles. Select at least two fiber bundles to execute.</string>
          </property>
          <property name="text">
           <string>Copy</string>
          </property>
         </widget>
        </item>
       </layout>
      </widget>
     </widget>
    </item>
    <item row="0" column="0">
     <widget class="QGroupBox" name="m_InputData">
      <property name="title">
       <string>Please Select Input Data</string>
      </property>
      <layout class="QGridLayout" name="gridLayout_9">
       <item row="0" column="1">
        <widget class="QLabel" name="m_FibLabel">
         <property name="text">
          <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; color:#ff0000;&quot;&gt;mandatory&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
         </property>
         <property name="wordWrap">
          <bool>true</bool>
         </property>
        </widget>
       </item>
       <item row="1" column="1">
        <widget class="QLabel" name="m_PfLabel">
         <property name="text">
          <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; color:#969696;&quot;&gt;needed for extraction&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
         </property>
         <property name="wordWrap">
          <bool>true</bool>
         </property>
        </widget>
       </item>
       <item row="0" column="0">
        <widget class="QLabel" name="label_2">
         <property name="toolTip">
          <string>Input DTI</string>
         </property>
         <property name="text">
          <string>Fiber Bundle:</string>
         </property>
        </widget>
       </item>
       <item row="1" column="0">
        <widget class="QLabel" name="label_6">
         <property name="toolTip">
          <string>Binary seed ROI. If not specified, the whole image area is seeded.</string>
         </property>
         <property name="text">
          <string>ROI:</string>
         </property>
        </widget>
       </item>
      </layout>
     </widget>
    </item>
    <item row="3" column="0">
     <spacer name="verticalSpacer">
      <property name="orientation">
       <enum>Qt::Vertical</enum>
      </property>
      <property name="sizeHint" stdset="0">
       <size>
        <width>20</width>
        <height>40</height>
       </size>
      </property>
     </spacer>
    </item>
   </layout>
  </widget>
  <customwidgets>
   <customwidget>
    <class>QmitkDataStorageComboBox</class>
    <extends>QComboBox</extends>
    <header location="global">QmitkDataStorageComboBox.h</header>
   </customwidget>
  </customwidgets>
  <resources>
   <include location="../../../org.mitk.gui.qt.diffusionimaging.fiberfox/resources/QmitkDiffusionImaging.qrc"/>
   <include location="../../resources/QmitkDiffusionImaging.qrc"/>
  </resources>
  <connections/>
 </ui>