diff --git a/Modules/Multilabel/mitkLabelSetImage.cpp b/Modules/Multilabel/mitkLabelSetImage.cpp
index ddc161f4af..c03f09a184 100644
--- a/Modules/Multilabel/mitkLabelSetImage.cpp
+++ b/Modules/Multilabel/mitkLabelSetImage.cpp
@@ -1,1672 +1,1659 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitkLabelSetImage.h"
 
-#include "mitkImageAccessByItk.h"
-#include "mitkImageCast.h"
-#include "mitkImagePixelReadAccessor.h"
-#include "mitkImagePixelWriteAccessor.h"
-#include "mitkInteractionConst.h"
-#include "mitkLookupTableProperty.h"
-#include "mitkPadImageFilter.h"
-#include "mitkRenderingManager.h"
-#include "mitkDICOMSegmentationPropertyHelper.h"
-#include "mitkDICOMQIPropertyHelper.h"
-
-#include <vtkCell.h>
-#include <vtkTransform.h>
-#include <vtkTransformPolyDataFilter.h>
-
-#include <itkImageRegionIterator.h>
-#include <itkQuadEdgeMesh.h>
-#include <itkTriangleMeshToBinaryImageFilter.h>
-#include <itkLabelGeometryImageFilter.h>
+#include <mitkImageAccessByItk.h>
+#include <mitkImageCast.h>
+#include <mitkImagePixelWriteAccessor.h>
+#include <mitkPadImageFilter.h>
+#include <mitkDICOMSegmentationPropertyHelper.h>
+#include <mitkDICOMQIPropertyHelper.h>
 
+#include <itkLabelGeometryImageFilter.h>
 #include <itkCommand.h>
-
 #include <itkBinaryFunctorImageFilter.h>
 
 
 namespace mitk
 {
   template <typename ImageType>
   void ClearBufferProcessing(ImageType* itkImage)
   {
     itkImage->FillBuffer(0);
   }
 
   void ClearImageBuffer(mitk::Image* image)
   {
     if (image->GetDimension() == 4)
     { //remark: this extra branch was added, because LabelSetImage instances can be
       //dynamic (4D), but AccessByItk by support only supports 2D and 3D.
       //The option to change the CMake default dimensions for AccessByItk was
       //dropped (for details see discussion in T28756)
       AccessFixedDimensionByItk(image, ClearBufferProcessing, 4);
     }
     else
     {
       AccessByItk(image, ClearBufferProcessing);
     }
   }
 }
 
 mitk::LabelSetImage::LabelSetImage()
   : mitk::Image(), m_UnlabeledLabelLock(false), m_ActiveLayer(0), m_activeLayerInvalid(false), m_ActiveLabelValue(0)
 {
   m_LookupTable = mitk::LookupTable::New();
   m_LookupTable->SetType(mitk::LookupTable::MULTILABEL);
 
   // Add some DICOM Tags as properties to segmentation image
   DICOMSegmentationPropertyHelper::DeriveDICOMSegmentationProperties(this);
 }
 
 mitk::LabelSetImage::LabelSetImage(const mitk::LabelSetImage &other)
   : Image(other),
     m_UnlabeledLabelLock(other.m_UnlabeledLabelLock),
     m_ActiveLayer(other.GetActiveLayer()),
     m_activeLayerInvalid(false),
     m_LookupTable(other.m_LookupTable->Clone()),
     m_ActiveLabelValue(other.m_ActiveLabelValue)
 {
   GroupIndexType i = 0;
   for (auto groupImage : other.m_LayerContainer)
   {
     this->AddLayer(groupImage->Clone(), other.GetConstLabelsByValue(other.GetLabelValuesByGroup(i)));
     i++;
   }
   m_Groups = other.m_Groups;
 
   // Add some DICOM Tags as properties to segmentation image
   DICOMSegmentationPropertyHelper::DeriveDICOMSegmentationProperties(this);
 }
 
 void mitk::LabelSetImage::Initialize(const mitk::Image *other)
 {
   mitk::PixelType pixelType(mitk::MakeScalarPixelType<LabelSetImage::PixelType>());
   if (other->GetDimension() == 2)
   {
     const unsigned int dimensions[] = {other->GetDimension(0), other->GetDimension(1), 1};
     Superclass::Initialize(pixelType, 3, dimensions);
   }
   else
   {
     Superclass::Initialize(pixelType, other->GetDimension(), other->GetDimensions());
   }
 
   auto originalGeometry = other->GetTimeGeometry()->Clone();
   this->SetTimeGeometry(originalGeometry);
 
   // initialize image memory to zero
   ClearImageBuffer(this);
 
   // Transfer some general DICOM properties from the source image to derived image (e.g. Patient information,...)
   DICOMQIPropertyHelper::DeriveDICOMSourceProperties(other, this);
 
   // Add a inital LabelSet ans corresponding image data to the stack
   if (this->GetNumberOfLayers() == 0)
   {
     AddLayer();
   }
 }
 
 mitk::LabelSetImage::~LabelSetImage()
 {
   for (auto [value, label] : m_LabelMap)
   {
     this->ReleaseLabel(label);
   }
   m_LabelMap.clear();
 }
 
 mitk::Image *mitk::LabelSetImage::GetLayerImage(unsigned int layer)
 {
   return m_LayerContainer[layer];
 }
 
 const mitk::Image *mitk::LabelSetImage::GetLayerImage(unsigned int layer) const
 {
   return m_LayerContainer[layer];
 }
 
 unsigned int mitk::LabelSetImage::GetActiveLayer() const
 {
   if (m_LayerContainer.size() == 0) mitkThrow() << "Cannot return active layer index. No layer is available.";
 
   return m_ActiveLayer;
 }
 
 unsigned int mitk::LabelSetImage::GetNumberOfLayers() const
 {
   return m_LayerContainer.size();
 }
 
 void mitk::LabelSetImage::RemoveGroup(GroupIndexType indexToDelete)
 {
   if (!this->ExistGroup(indexToDelete)) mitkThrow() << "Cannot remove group. Group does not exist. Invalid group index: "<<indexToDelete;
 
   const auto activeIndex = GetActiveLayer();
 
   auto newActiveIndex = activeIndex;
   auto newActiveIndexBeforeDeletion = activeIndex;
   //determin new active group index (afte the group will be removed);
   if (indexToDelete < activeIndex)
   { //lower the index because position in m_LayerContainer etc has changed
     newActiveIndex = activeIndex-1;
   }
   else if (indexToDelete == activeIndex)
   {
     if (this->GetNumberOfLayers() == 1)
     { //last layer is about to be deleted
       newActiveIndex = 0;
     }
     else
     {
       //we have to add/substract one more because we have not removed the layer yet, thus the group count is to 1 high.
       newActiveIndex = indexToDelete+1 < GetNumberOfLayers() ? indexToDelete : GetNumberOfLayers() - 2;
       newActiveIndexBeforeDeletion = indexToDelete + 1 < GetNumberOfLayers() ? indexToDelete+1 : indexToDelete -1;
     }
   }
 
   if (activeIndex == indexToDelete)
   {
     // we are deleting the active layer, it should not be copied back into the vector
     m_activeLayerInvalid = true;
     //copy the image content of the upcoming new active layer; 
     SetActiveLayer(newActiveIndexBeforeDeletion);
   }
 
   auto relevantLabels = m_GroupToLabelMap[indexToDelete];
 
   // remove labels of group
   for (auto labelValue : relevantLabels)
   {
     auto label = m_LabelMap[labelValue];
     this->ReleaseLabel(label);
     m_LabelToGroupMap.erase(labelValue);
     m_LabelMap.erase(labelValue);
     this->InvokeEvent(LabelRemovedEvent(labelValue));
   }
   // remove the group entries in the maps and the image.
   m_Groups.erase(m_Groups.begin() + indexToDelete);
   m_GroupToLabelMap.erase(m_GroupToLabelMap.begin() + indexToDelete);
   m_LayerContainer.erase(m_LayerContainer.begin() + indexToDelete);
 
   //update old indeces in m_GroupToLabelMap to new layer indices
   for (auto& element : m_LabelToGroupMap)
   {
     if (element.second > indexToDelete) element.second = element.second -1;
   }
 
   //correct active layer index
   m_ActiveLayer = newActiveIndex;
 
   this->InvokeEvent(LabelsChangedEvent(relevantLabels));
   this->InvokeEvent(GroupRemovedEvent(indexToDelete));
   this->Modified();
 }
 
 mitk::LabelSetImage::LabelValueVectorType mitk::LabelSetImage::ExtractLabelValuesFromLabelVector(const LabelVectorType& labels)
 {
   LabelValueVectorType result;
 
   for (auto label : labels)
   {
     result.emplace_back(label->GetValue());
   }
   return result;
 }
 
 mitk::LabelSetImage::LabelValueVectorType mitk::LabelSetImage::ExtractLabelValuesFromLabelVector(const ConstLabelVectorType& labels)
 {
   LabelValueVectorType result;
 
   for (auto label : labels)
   {
     result.emplace_back(label->GetValue());
   }
   return result;
 }
 
 mitk::LabelSetImage::ConstLabelVectorType mitk::LabelSetImage::ConvertLabelVectorConst(const LabelVectorType& labels)
 {
   ConstLabelVectorType result(labels.begin(), labels.end());
   return result;
 };
 
 const mitk::LabelSetImage::LabelValueVectorType mitk::LabelSetImage::GetAllLabelValues() const
 {
   LabelValueVectorType result;
 
   for (auto [value, label] : m_LabelMap)
   {
     result.emplace_back(value);
   }
   return result;
 }
 
 mitk::LabelSetImage::LabelValueVectorType mitk::LabelSetImage::GetUsedLabelValues() const
 {
   LabelValueVectorType result = { UNLABELED_VALUE };
 
   for (auto [value, label] : m_LabelMap)
   {
     result.emplace_back(value);
   }
 
   return result;
 }
 
 mitk::LabelSetImage::GroupIndexType mitk::LabelSetImage::AddLayer(ConstLabelVector labels)
 {
   mitk::Image::Pointer newImage = mitk::Image::New();
   newImage->Initialize(this->GetPixelType(),
                        this->GetDimension(),
                        this->GetDimensions(),
                        this->GetImageDescriptor()->GetNumberOfChannels());
   newImage->SetTimeGeometry(this->GetTimeGeometry()->Clone());
 
   ClearImageBuffer(newImage);
 
   return this->AddLayer(newImage, labels);
 }
 
 mitk::LabelSetImage::GroupIndexType mitk::LabelSetImage::AddLayer(mitk::Image::Pointer layerImage, ConstLabelVector labels)
 {
   GroupIndexType newGroupID = m_Groups.size();
 
   // push a new working image for the new layer
   m_LayerContainer.push_back(layerImage);
 
   m_Groups.push_back("");
   m_GroupToLabelMap.push_back({});
 
   for (auto label : labels)
   {
     if (m_LabelMap.end() != m_LabelMap.find(label->GetValue()))
     {
       mitkThrow() << "Cannot add layer. Labels that should be added with layer use at least one label value that is already in use. Conflicted label value: " << label->GetValue();
     }
 
     auto labelClone = label->Clone();
 
     DICOMSegmentationPropertyHelper::SetDICOMSegmentProperties(labelClone);
     this->AddLabelToMap(labelClone->GetValue(), labelClone, newGroupID);
     this->RegisterLabel(labelClone);
   }
 
   this->Modified();
   this->InvokeEvent(GroupAddedEvent(newGroupID));
 
   return newGroupID;
 }
 
 void mitk::LabelSetImage::ReplaceGroupLabels(const GroupIndexType groupID, const ConstLabelVectorType& labelSet)
 {
   if (m_LayerContainer.size() <= groupID)
   {
     mitkThrow() << "Trying to replace labels of non-exising group. Invalid group id: "<<groupID;
   }
 
   //remove old group labels
   auto oldLabels = this->m_GroupToLabelMap[groupID];
   for (auto labelID : oldLabels)
   {
     this->RemoveLabelFromMap(labelID);
     this->InvokeEvent(LabelRemovedEvent(labelID));
 
   }
   this->InvokeEvent(LabelsChangedEvent(oldLabels));
   this->InvokeEvent(GroupModifiedEvent(groupID));
 
   //add new labels to group
   for (auto label : labelSet)
   {
     this->AddLabel(label->Clone(), groupID, true, false);
   }
 }
 
 void mitk::LabelSetImage::ReplaceGroupLabels(const GroupIndexType groupID, const LabelVectorType& labelSet)
 {
   return ReplaceGroupLabels(groupID, ConvertLabelVectorConst(labelSet));
 }
 
 mitk::Image* mitk::LabelSetImage::GetGroupImage(GroupIndexType groupID)
 {
   if (!this->ExistGroup(groupID)) mitkThrow() << "Error, cannot return group image. Group ID is invalid. Invalid ID: " << groupID;
 
   return groupID == this->GetActiveLayer() ? this : m_LayerContainer[groupID];
 }
 
 const mitk::Image* mitk::LabelSetImage::GetGroupImage(GroupIndexType groupID) const
 {
   if (!this->ExistGroup(groupID)) mitkThrow() << "Error, cannot return group image. Group ID is invalid. Invalid ID: " << groupID;
 
   return groupID == this->GetActiveLayer() ? this : m_LayerContainer[groupID].GetPointer();
 }
 
 void mitk::LabelSetImage::SetActiveLayer(unsigned int layer)
 {
   try
   {
     if (4 == this->GetDimension())
     {
       if ((layer != GetActiveLayer() || m_activeLayerInvalid) && (layer < this->GetNumberOfLayers()))
       {
         BeforeChangeLayerEvent.Send();
 
         if (m_activeLayerInvalid)
         {
           // We should not write the invalid layer back to the vector
           m_activeLayerInvalid = false;
         }
         else
         {
           AccessFixedDimensionByItk_n(this, ImageToLayerContainerProcessing, 4, (GetActiveLayer()));
         }
         m_ActiveLayer = layer;
         AccessFixedDimensionByItk_n(this, LayerContainerToImageProcessing, 4, (GetActiveLayer()));
 
         AfterChangeLayerEvent.Send();
       }
     }
     else
     {
       if ((layer != GetActiveLayer() || m_activeLayerInvalid) && (layer < this->GetNumberOfLayers()))
       {
         BeforeChangeLayerEvent.Send();
 
         if (m_activeLayerInvalid)
         {
           // We should not write the invalid layer back to the vector
           m_activeLayerInvalid = false;
         }
         else
         {
           AccessByItk_1(this, ImageToLayerContainerProcessing, GetActiveLayer());
         }
         m_ActiveLayer = layer;
         AccessByItk_1(this, LayerContainerToImageProcessing, GetActiveLayer());
 
         AfterChangeLayerEvent.Send();
       }
     }
   }
   catch (itk::ExceptionObject &e)
   {
     mitkThrow() << e.GetDescription();
   }
   this->Modified();
 }
 
 void mitk::LabelSetImage::SetActiveLabel(LabelValueType label)
 {
   m_ActiveLabelValue = label;
 
   if (label != UNLABELED_VALUE)
   {
     auto groupID = this->GetGroupIndexOfLabel(label);
     if (groupID!=this->GetActiveLayer()) this->SetActiveLayer(groupID);
   }
   Modified();
 }
 
 void mitk::LabelSetImage::ClearBuffer()
 {
   try
   {
     ClearImageBuffer(this);
     this->Modified();
   }
   catch (itk::ExceptionObject &e)
   {
     mitkThrow() << e.GetDescription();
   }
 }
 
 bool mitk::LabelSetImage::ExistLabelSet(unsigned int layer) const
 {
   return layer < m_LayerContainer.size();
 }
 
 void mitk::LabelSetImage::MergeLabel(PixelType pixelValue, PixelType sourcePixelValue, unsigned int layer)
 {
   try
   {
     AccessByItk_2(this, MergeLabelProcessing, pixelValue, sourcePixelValue);
   }
   catch (itk::ExceptionObject &e)
   {
     mitkThrow() << e.GetDescription();
   }
   this->SetActiveLabel(pixelValue);
   this->InvokeEvent(LabelModifiedEvent(sourcePixelValue));
   this->InvokeEvent(LabelModifiedEvent(pixelValue));
   this->InvokeEvent(LabelsChangedEvent({ sourcePixelValue, pixelValue }));
   Modified();
 }
 
 void mitk::LabelSetImage::MergeLabels(PixelType pixelValue, const std::vector<PixelType>& vectorOfSourcePixelValues, unsigned int layer)
 {
   try
   {
     for (unsigned int idx = 0; idx < vectorOfSourcePixelValues.size(); idx++)
     {
       AccessByItk_2(this, MergeLabelProcessing, pixelValue, vectorOfSourcePixelValues[idx]);
       this->InvokeEvent(LabelModifiedEvent(vectorOfSourcePixelValues[idx]));
     }
   }
   catch (itk::ExceptionObject &e)
   {
     mitkThrow() << e.GetDescription();
   }
   this->SetActiveLabel(pixelValue);
   this->InvokeEvent(LabelModifiedEvent(pixelValue));
   auto modifiedValues = vectorOfSourcePixelValues;
   modifiedValues.push_back(pixelValue);
   this->InvokeEvent(LabelsChangedEvent(modifiedValues));
 
   Modified();
 }
 
 void mitk::LabelSetImage::RemoveLabel(LabelValueType pixelValue)
 {
   if (m_LabelMap.find(pixelValue) == m_LabelMap.end()) return;
 
   auto groupID = this->GetGroupIndexOfLabel(pixelValue);
 
   //first erase the pixel content (also triggers a LabelModified event)
   this->EraseLabel(pixelValue);
   this->RemoveLabelFromMap(pixelValue);
 
 
   if (m_ActiveLabelValue == pixelValue)
   {
     this->SetActiveLabel(0);
   }
 
   this->InvokeEvent(LabelRemovedEvent(pixelValue));
   this->InvokeEvent(LabelsChangedEvent({ pixelValue }));
   this->InvokeEvent(GroupModifiedEvent(groupID));
 }
 
 void mitk::LabelSetImage::RemoveLabelFromMap(LabelValueType pixelValue)
 {
   if (m_LabelMap.find(pixelValue) == m_LabelMap.end()) mitkThrow()<<"Invalid state of of instance. RemoveLabelFromMap was called for unkown label id. invalid label id: "<<pixelValue;
 
   auto groupID = this->GetGroupIndexOfLabel(pixelValue);
 
   this->ReleaseLabel(m_LabelMap[pixelValue]);
   //now remove the label entry itself
   m_LabelMap.erase(pixelValue);
   m_LabelToGroupMap.erase(pixelValue);
   auto labelsInGroup = m_GroupToLabelMap[groupID];
   labelsInGroup.erase(std::remove(labelsInGroup.begin(), labelsInGroup.end(), pixelValue), labelsInGroup.end());
   m_GroupToLabelMap[groupID] = labelsInGroup;
 }
 
 void mitk::LabelSetImage::RemoveLabels(const LabelValueVectorType& vectorOfLabelPixelValues)
 {
   for (const auto labelValue : vectorOfLabelPixelValues)
   {
     this->RemoveLabel(labelValue);
   }
   this->InvokeEvent(LabelsChangedEvent(vectorOfLabelPixelValues));
 }
 
 void mitk::LabelSetImage::EraseLabel(PixelType pixelValue)
 {
   try
   {
     auto groupID = this->GetGroupIndexOfLabel(pixelValue);
 
     mitk::Image* groupImage = this->GetActiveLayer() != groupID
        ? this->GetLayerImage(groupID)
        : this;
 
     if (4 == this->GetDimension())
     {
       AccessFixedDimensionByItk_1(groupImage, EraseLabelProcessing, 4, pixelValue);
     }
     else
     {
       AccessByItk_1(groupImage, EraseLabelProcessing, pixelValue);
     }
   }
   catch (const itk::ExceptionObject& e)
   {
     mitkThrow() << e.GetDescription();
   }
 
   this->InvokeEvent(LabelModifiedEvent(pixelValue));
   this->InvokeEvent(LabelsChangedEvent({ pixelValue }));
   Modified();
 }
 
 void mitk::LabelSetImage::EraseLabels(const std::vector<PixelType>& VectorOfLabelPixelValues)
 {
   for (unsigned int idx = 0; idx < VectorOfLabelPixelValues.size(); idx++)
   {
     this->EraseLabel(VectorOfLabelPixelValues[idx]);
   }
 }
 
 mitk::LabelSetImage::LabelValueType mitk::LabelSetImage::GetUnusedLabelValue() const
 {
   auto usedValues = this->GetUsedLabelValues();
   return usedValues.back() + 1;
 }
 
 mitk::Label* mitk::LabelSetImage::AddLabel(mitk::Label* label, GroupIndexType groupID, bool addAsClone, bool correctLabelValue)
 {
   unsigned int max_size = mitk::Label::MAX_LABEL_VALUE + 1;
   if (m_LayerContainer.size() >= max_size)
     return nullptr;
 
   mitk::Label::Pointer newLabel = addAsClone ? label->Clone() : Label::Pointer(label);
 
   auto pixelValue = newLabel->GetValue();
   auto usedValues = this->GetUsedLabelValues();
   auto finding = std::find(usedValues.begin(), usedValues.end(), pixelValue);
 
   if (!usedValues.empty() && usedValues.end() != finding)
   {
     if (correctLabelValue)
     {
       pixelValue = this->GetUnusedLabelValue();
       newLabel->SetValue(pixelValue);
     }
     else
     {
       mitkThrow() << "Cannot add label due to conflicting label value that already exists in the MultiLabelSegmentation. Conflicting label value: " << pixelValue;
     }
   }
 
   // add DICOM information of the label
   DICOMSegmentationPropertyHelper::SetDICOMSegmentProperties(newLabel);
 
   this->AddLabelToMap(pixelValue, newLabel, groupID);
   this->RegisterLabel(newLabel);
 
   this->InvokeEvent(LabelAddedEvent(newLabel->GetValue()));
   m_ActiveLabelValue = newLabel->GetValue();
   this->Modified();
 
   return newLabel;
 }
 
 mitk::Label* mitk::LabelSetImage::AddLabel(const std::string& name, const mitk::Color& color, GroupIndexType groupID)
 {
   mitk::Label::Pointer newLabel = mitk::Label::New();
   newLabel->SetName(name);
   newLabel->SetColor(color);
   return AddLabel(newLabel,groupID,false);
 }
 
 void mitk::LabelSetImage::RenameLabel(PixelType pixelValue, const std::string& name, const mitk::Color& color)
 {
   mitk::Label* label = GetLabel(pixelValue);
   label->SetName(name);
   label->SetColor(color);
 
   this->UpdateLookupTable(pixelValue);
   // change DICOM information of the label
   DICOMSegmentationPropertyHelper::SetDICOMSegmentProperties(label);
 }
 
 mitk::Label *mitk::LabelSetImage::GetActiveLabel()
 {
   if (m_ActiveLabelValue == UNLABELED_VALUE) return nullptr;
 
   auto finding = m_LabelMap.find(m_ActiveLabelValue);
   return finding == m_LabelMap.end() ? nullptr : finding->second;
 }
 
 const mitk::Label* mitk::LabelSetImage::GetActiveLabel() const
 {
   if (m_ActiveLabelValue == UNLABELED_VALUE) return nullptr;
 
   auto finding = m_LabelMap.find(m_ActiveLabelValue);
   return finding == m_LabelMap.end() ? nullptr : finding->second;
 }
 
 void mitk::LabelSetImage::UpdateCenterOfMass(PixelType pixelValue)
 {
   if (4 == this->GetDimension())
   {
     AccessFixedDimensionByItk_1(this->GetGroupImage(this->GetGroupIndexOfLabel(pixelValue)), CalculateCenterOfMassProcessing, 4, pixelValue);
   }
   else
   {
     AccessByItk_1(this->GetGroupImage(this->GetGroupIndexOfLabel(pixelValue)), CalculateCenterOfMassProcessing, pixelValue);
   }
 }
 
 void mitk::LabelSetImage::SetLookupTable(mitk::LookupTable* lut)
 {
   m_LookupTable = lut;
   this->Modified();
 }
 
 void mitk::LabelSetImage::UpdateLookupTable(PixelType pixelValue)
 {
   const mitk::Color& color = this->GetLabel(pixelValue)->GetColor();
 
   double rgba[4];
   m_LookupTable->GetTableValue(static_cast<int>(pixelValue), rgba);
   rgba[0] = color.GetRed();
   rgba[1] = color.GetGreen();
   rgba[2] = color.GetBlue();
   if (GetLabel(pixelValue)->GetVisible())
     rgba[3] = GetLabel(pixelValue)->GetOpacity();
   else
     rgba[3] = 0.0;
   m_LookupTable->SetTableValue(static_cast<int>(pixelValue), rgba);
 }
 
 unsigned int mitk::LabelSetImage::GetNumberOfLabels(unsigned int layer) const
 {
   return m_GroupToLabelMap[layer].size();
 }
 
 unsigned int mitk::LabelSetImage::GetTotalNumberOfLabels() const
 {
   return m_LabelMap.size();
 }
 
 void mitk::LabelSetImage::MaskStamp(mitk::Image *mask, bool forceOverwrite)
 {
   try
   {
     mitk::PadImageFilter::Pointer padImageFilter = mitk::PadImageFilter::New();
     padImageFilter->SetInput(0, mask);
     padImageFilter->SetInput(1, this);
     padImageFilter->SetPadConstant(0);
     padImageFilter->SetBinaryFilter(false);
     padImageFilter->SetLowerThreshold(0);
     padImageFilter->SetUpperThreshold(1);
 
     padImageFilter->Update();
 
     mitk::Image::Pointer paddedMask = padImageFilter->GetOutput();
 
     if (paddedMask.IsNull())
       return;
 
     AccessByItk_2(this, MaskStampProcessing, paddedMask, forceOverwrite);
   }
   catch (...)
   {
     mitkThrow() << "Could not stamp the provided mask on the selected label.";
   }
 }
 
 mitk::Image::Pointer mitk::LabelSetImage::CreateLabelMask(PixelType index)
 {
   if (!this->ExistLabel(index)) mitkThrow() << "Error, cannot return label mask. Label ID is invalid. Invalid ID: " << index;
 
   auto mask = mitk::Image::New();
 
   // mask->Initialize(this) does not work here if this label set image has a single slice,
   // since the mask would be automatically flattened to a 2-d image, whereas we expect the
   // original dimension of this label set image. Hence, initialize the mask more explicitly:
   mask->Initialize(this->GetPixelType(), this->GetDimension(), this->GetDimensions());
   mask->SetTimeGeometry(this->GetTimeGeometry()->Clone());
 
   ClearImageBuffer(mask);
 
   const auto groupID = this->GetGroupIndexOfLabel(index);
 
   auto destinationLabel = this->GetLabel(index)->Clone();
   destinationLabel->SetValue(1);
 
   TransferLabelContent(this->GetGroupImage(groupID), mask.GetPointer(),
     {destinationLabel},
     LabelSetImage::UNLABELED_VALUE, LabelSetImage::UNLABELED_VALUE, false,
     { { index, destinationLabel->GetValue()}}, MultiLabelSegmentation::MergeStyle::Replace, MultiLabelSegmentation::OverwriteStyle::IgnoreLocks);
 
   return mask;
 }
 
 void mitk::LabelSetImage::InitializeByLabeledImage(mitk::Image::Pointer image)
 {
   if (image.IsNull() || image->IsEmpty() || !image->IsInitialized())
     mitkThrow() << "Invalid labeled image.";
 
   try
   {
     this->Initialize(image);
 
     unsigned int byteSize = sizeof(LabelSetImage::PixelType);
     for (unsigned int dim = 0; dim < image->GetDimension(); ++dim)
     {
       byteSize *= image->GetDimension(dim);
     }
 
     mitk::ImageWriteAccessor *accessor = new mitk::ImageWriteAccessor(static_cast<mitk::Image *>(this));
     memset(accessor->GetData(), 0, byteSize);
     delete accessor;
 
     auto geometry = image->GetTimeGeometry()->Clone();
     this->SetTimeGeometry(geometry);
 
     if (image->GetDimension() == 3)
     {
       AccessTwoImagesFixedDimensionByItk(this, image, InitializeByLabeledImageProcessing, 3);
     }
     else if (image->GetDimension() == 4)
     {
       AccessTwoImagesFixedDimensionByItk(this, image, InitializeByLabeledImageProcessing, 4);
     }
     else
     {
       mitkThrow() << image->GetDimension() << "-dimensional label set images not yet supported";
     }
   }
   catch (Exception e)
   {
     mitkReThrow(e) << "Could not intialize by provided labeled image.";
   }
   catch (...)
   {
     mitkThrow() << "Could not intialize by provided labeled image due to unkown error.";
   }
   this->Modified();
 }
 
 template <typename LabelSetImageType, typename ImageType>
 void mitk::LabelSetImage::InitializeByLabeledImageProcessing(LabelSetImageType *labelSetImage, ImageType *image)
 {
   typedef itk::ImageRegionConstIteratorWithIndex<ImageType> SourceIteratorType;
   typedef itk::ImageRegionIterator<LabelSetImageType> TargetIteratorType;
 
   TargetIteratorType targetIter(labelSetImage, labelSetImage->GetRequestedRegion());
   targetIter.GoToBegin();
 
   SourceIteratorType sourceIter(image, image->GetRequestedRegion());
   sourceIter.GoToBegin();
 
   while (!sourceIter.IsAtEnd())
   {
     const auto originalSourceValue = sourceIter.Get();
     const auto sourceValue = static_cast<PixelType>(originalSourceValue);
 
     if (originalSourceValue > mitk::Label::MAX_LABEL_VALUE)
     {
       mitkThrow() << "Cannot initialize MultiLabelSegmentation by image. Image contains a pixel value that exceeds the label value range. Invalid pixel value:" << originalSourceValue;
     }
 
     targetIter.Set(sourceValue);
 
     if (LabelSetImage::UNLABELED_VALUE!=sourceValue && !this->ExistLabel(sourceValue))
     {
       if (this->GetTotalNumberOfLabels() >= mitk::Label::MAX_LABEL_VALUE)
       {
         mitkThrow() << "Cannot initialize MultiLabelSegmentation by image. Image contains to many labels.";
       }
 
       std::stringstream name;
       name << "object-" << sourceValue;
 
       double rgba[4];
       this->GetLookupTable()->GetTableValue(sourceValue, rgba);
 
       mitk::Color color;
       color.SetRed(rgba[0]);
       color.SetGreen(rgba[1]);
       color.SetBlue(rgba[2]);
 
       auto label = mitk::Label::New();
       label->SetName(name.str().c_str());
       label->SetColor(color);
       label->SetOpacity(rgba[3]);
       label->SetValue(sourceValue);
 
       this->AddLabel(label,0,false);
     }
 
     ++sourceIter;
     ++targetIter;
   }
 }
 
 template <typename ImageType>
 void mitk::LabelSetImage::MaskStampProcessing(ImageType *itkImage, mitk::Image *mask, bool forceOverwrite)
 {
   typename ImageType::Pointer itkMask;
   mitk::CastToItkImage(mask, itkMask);
 
   typedef itk::ImageRegionConstIterator<ImageType> SourceIteratorType;
   typedef itk::ImageRegionIterator<ImageType> TargetIteratorType;
 
   SourceIteratorType sourceIter(itkMask, itkMask->GetLargestPossibleRegion());
   sourceIter.GoToBegin();
 
   TargetIteratorType targetIter(itkImage, itkImage->GetLargestPossibleRegion());
   targetIter.GoToBegin();
 
   const auto activeLabel = this->GetActiveLabel()->GetValue();
 
   while (!sourceIter.IsAtEnd())
   {
     PixelType sourceValue = sourceIter.Get();
     PixelType targetValue = targetIter.Get();
 
     if ((sourceValue != UNLABELED_VALUE) &&
         (forceOverwrite || !this->IsLabelLocked(targetValue))) // skip unlabeled pixels and locked labels
     {
       targetIter.Set(activeLabel);
     }
     ++sourceIter;
     ++targetIter;
   }
 
   this->Modified();
 }
 
 template <typename ImageType>
 void mitk::LabelSetImage::CalculateCenterOfMassProcessing(ImageType *itkImage, LabelValueType pixelValue)
 {
   if (ImageType::GetImageDimension() != 3)
   {
     return;
   }
 
   auto labelGeometryFilter = itk::LabelGeometryImageFilter<ImageType>::New();
   labelGeometryFilter->SetInput(itkImage);
   labelGeometryFilter->Update();
   auto centroid = labelGeometryFilter->GetCentroid(pixelValue);
 
   mitk::Point3D pos;
   pos[0] = centroid[0];
   pos[1] = centroid[1];
   pos[2] = centroid[2];
 
   this->GetLabel(pixelValue)->SetCenterOfMassIndex(pos);
   this->GetSlicedGeometry()->IndexToWorld(pos, pos);
   this->GetLabel(pixelValue)->SetCenterOfMassCoordinates(pos);
 }
 
 template <typename TPixel, unsigned int VImageDimension>
 void mitk::LabelSetImage::LayerContainerToImageProcessing(itk::Image<TPixel, VImageDimension> *target,
                                                           unsigned int layer)
 {
   typedef itk::Image<TPixel, VImageDimension> ImageType;
   typename ImageType::Pointer itkSource;
   // mitk::CastToItkImage(m_LayerContainer[layer], itkSource);
   itkSource = ImageToItkImage<TPixel, VImageDimension>(m_LayerContainer[layer]);
   typedef itk::ImageRegionConstIterator<ImageType> SourceIteratorType;
   typedef itk::ImageRegionIterator<ImageType> TargetIteratorType;
 
   SourceIteratorType sourceIter(itkSource, itkSource->GetLargestPossibleRegion());
   sourceIter.GoToBegin();
 
   TargetIteratorType targetIter(target, target->GetLargestPossibleRegion());
   targetIter.GoToBegin();
 
   while (!sourceIter.IsAtEnd())
   {
     targetIter.Set(sourceIter.Get());
     ++sourceIter;
     ++targetIter;
   }
 }
 
 template <typename TPixel, unsigned int VImageDimension>
 void mitk::LabelSetImage::ImageToLayerContainerProcessing(itk::Image<TPixel, VImageDimension> *source,
                                                           unsigned int layer) const
 {
   typedef itk::Image<TPixel, VImageDimension> ImageType;
   typename ImageType::Pointer itkTarget;
   // mitk::CastToItkImage(m_LayerContainer[layer], itkTarget);
   itkTarget = ImageToItkImage<TPixel, VImageDimension>(m_LayerContainer[layer]);
 
   typedef itk::ImageRegionConstIterator<ImageType> SourceIteratorType;
   typedef itk::ImageRegionIterator<ImageType> TargetIteratorType;
 
   SourceIteratorType sourceIter(source, source->GetLargestPossibleRegion());
   sourceIter.GoToBegin();
 
   TargetIteratorType targetIter(itkTarget, itkTarget->GetLargestPossibleRegion());
   targetIter.GoToBegin();
 
   while (!sourceIter.IsAtEnd())
   {
     targetIter.Set(sourceIter.Get());
     ++sourceIter;
     ++targetIter;
   }
 }
 
 template <typename ImageType>
 void mitk::LabelSetImage::EraseLabelProcessing(ImageType *itkImage, PixelType pixelValue)
 {
   typedef itk::ImageRegionIterator<ImageType> IteratorType;
 
   IteratorType iter(itkImage, itkImage->GetLargestPossibleRegion());
   iter.GoToBegin();
 
   while (!iter.IsAtEnd())
   {
     PixelType value = iter.Get();
 
     if (value == pixelValue)
     {
       iter.Set(0);
     }
     ++iter;
   }
 }
 
 template <typename ImageType>
 void mitk::LabelSetImage::MergeLabelProcessing(ImageType *itkImage, PixelType pixelValue, PixelType index)
 {
   typedef itk::ImageRegionIterator<ImageType> IteratorType;
 
   IteratorType iter(itkImage, itkImage->GetLargestPossibleRegion());
   iter.GoToBegin();
 
   while (!iter.IsAtEnd())
   {
     if (iter.Get() == index)
     {
       iter.Set(pixelValue);
     }
     ++iter;
   }
 }
 
 void mitk::LabelSetImage::AddLabelToMap(LabelValueType labelValue, mitk::Label* label, GroupIndexType groupID)
 {
   if (m_LabelMap.find(labelValue)!=m_LabelMap.end())
     mitkThrow() << "Segmentation is in an invalid state: Label value collision. A label was added with a LabelValue already in use. LabelValue: " << labelValue;
 
   if (!this->ExistGroup(groupID))
     mitkThrow() << "Cannot add label. Defined group is unkown. Invalid group index: " << groupID;
 
   m_LabelMap[labelValue] = label;
   m_LabelToGroupMap[labelValue] = groupID;
   auto groupFinding = std::find(m_GroupToLabelMap[groupID].begin(), m_GroupToLabelMap[groupID].end(), labelValue);
   if (groupFinding == m_GroupToLabelMap[groupID].end())
   {
     m_GroupToLabelMap[groupID].push_back(labelValue);
   }
 }
 
 void mitk::LabelSetImage::RegisterLabel(mitk::Label* label)
 {
   UpdateLookupTable(label->GetValue());
 
   auto command = itk::MemberCommand<LabelSetImage>::New();
   command->SetCallbackFunction(this, &LabelSetImage::OnLabelModified);
   label->AddObserver(itk::ModifiedEvent(), command);
 }
 
 void mitk::LabelSetImage::ReleaseLabel(Label* label)
 {
   if (nullptr == label) mitkThrow() << "Invalid call of ReleaseLabel with a nullptr.";
   label->RemoveAllObservers();
 }
 
 void mitk::LabelSetImage::ApplyToLabels(const LabelValueVectorType& values, std::function<void(Label*)>&& lambda)
 {
   auto labels = this->GetLabelsByValue(values);
   std::for_each(labels.begin(), labels.end(), lambda);
   this->InvokeEvent(LabelsChangedEvent(values));
 }
 
 void mitk::LabelSetImage::VisitLabels(const LabelValueVectorType& values, std::function<void(const Label*)>&& lambda) const
 {
   auto labels = this->GetConstLabelsByValue(values);
   std::for_each(labels.begin(), labels.end(), lambda);
 }
 
 
 void mitk::LabelSetImage::OnLabelModified(const Object* sender, const itk::EventObject&)
 {
   auto label = dynamic_cast<const Label*>(sender);
   if (nullptr == label)
     mitkThrow() << "LabelSet is in wrong state. LabelModified event is not send by a label instance.";
 
   Superclass::Modified();
   this->InvokeEvent(LabelModifiedEvent(label->GetValue()));
 }
 
 bool mitk::LabelSetImage::ExistLabel(LabelValueType value) const
 {
   auto finding = m_LabelMap.find(value);
   return m_LabelMap.end() != finding;
 }
 
 bool mitk::LabelSetImage::ExistLabel(LabelValueType value, GroupIndexType groupIndex) const
 {
   auto finding = m_LabelToGroupMap.find(value);
   if (m_LabelToGroupMap.end() != finding)
   {
     return finding->second == groupIndex;
   }
   return false;
 }
 
 bool mitk::LabelSetImage::ExistGroup(GroupIndexType index) const
 {
   return index < m_LayerContainer.size();
 }
 
 bool mitk::LabelSetImage::IsLabelInGroup(LabelValueType value) const
 {
   GroupIndexType dummy;
   return this->IsLabelInGroup(value, dummy);
 }
 
 bool mitk::LabelSetImage::IsLabelInGroup(LabelValueType value, GroupIndexType& groupIndex) const
 {
   auto finding = m_LabelToGroupMap.find(value);
   if (m_LabelToGroupMap.end() != finding)
   {
     groupIndex = finding->second;
     return true;
   }
   return false;
 }
 
 mitk::LabelSetImage::GroupIndexType mitk::LabelSetImage::GetGroupIndexOfLabel(LabelValueType value) const
 {
   auto finding = m_LabelToGroupMap.find(value);
   if (m_LabelToGroupMap.end() == finding)
   {
     mitkThrow()<< "Cannot deduce group index. Passed label value does not exist. Value: "<< value;
   }
   return finding->second;
 }
 
 
 const mitk::Label* mitk::LabelSetImage::GetLabel(LabelValueType value) const
 {
   auto finding = m_LabelMap.find(value);
   if (m_LabelMap.end() != finding)
   {
     return finding->second;
   }
   return nullptr;
 };
 
 mitk::Label* mitk::LabelSetImage::GetLabel(LabelValueType value)
 {
   auto finding = m_LabelMap.find(value);
   if (m_LabelMap.end() != finding)
   {
     return finding->second;
   }
   return nullptr;
 };
 
 bool mitk::LabelSetImage::IsLabelLocked(LabelValueType value) const
 {
   if (value == UNLABELED_VALUE)
   {
     return m_UnlabeledLabelLock;
   }
 
   const auto label = this->GetLabel(value);
   return label->GetLocked();
 }
 
 const mitk::LabelSetImage::ConstLabelVectorType mitk::LabelSetImage::GetLabels() const
 {
   ConstLabelVectorType result;
   for (auto [value, label] : m_LabelMap)
   {
     result.emplace_back(label);
   }
   return result;
 }
 
 const mitk::LabelSetImage::LabelVectorType mitk::LabelSetImage::GetLabels()
 {
   LabelVectorType result;
   for (auto [value, label] : m_LabelMap)
   {
     result.emplace_back(label);
   }
   return result;
 }
 
 const mitk::LabelSetImage::LabelVectorType mitk::LabelSetImage::GetLabelsByValue(const LabelValueVectorType& labelValues, bool ignoreMissing)
 {
   LabelVectorType result;
   for (const auto& labelValue : labelValues)
   {
     auto* label = this->GetLabel(labelValue);
 
     if (label != nullptr)
     {
       result.emplace_back(label);
     }
     else if (!ignoreMissing) mitkThrow() << "Error cannot get labels by Value. At least one passed value is unknown. Unknown value: " << labelValue;
   }
   return result;
 }
 
 const mitk::LabelSetImage::ConstLabelVectorType mitk::LabelSetImage::GetConstLabelsByValue(const LabelValueVectorType& labelValues, bool ignoreMissing) const
 {
   ConstLabelVectorType result;
   for (const auto& labelValue : labelValues)
   {
     const auto* label = this->GetLabel(labelValue);
 
     if (label != nullptr)
     {
       result.emplace_back(label);
     }
     else if (!ignoreMissing) mitkThrow() << "Error cannot get labels by Value. At least one passed value is unknown. Unknown value: " << labelValue;
   }
   return result;
 }
 
 const mitk::LabelSetImage::LabelValueVectorType mitk::LabelSetImage::GetLabelValuesByGroup(GroupIndexType index) const
 {
   if (!this->ExistGroup(index))
     mitkThrow() << "Cannot get labels of an invalid group. Invalid group index: " << index;
 
   return m_GroupToLabelMap[index];
 }
 
 const mitk::LabelSetImage::LabelValueVectorType mitk::LabelSetImage::GetLabelValuesByName(GroupIndexType index, std::string_view name) const
 {
   LabelValueVectorType result;
 
   auto searchName = [&result, name](const Label* l) { if(l->GetName() == name) result.push_back(l->GetValue()); };
 
   this->VisitLabels(this->GetLabelValuesByGroup(index), searchName);
 
   return result;
 }
 
 std::vector<std::string> mitk::LabelSetImage::GetLabelClassNames() const
 {
   std::set<std::string> names;
   auto searchName = [&names](const Label* l) { names.emplace(l->GetName()); };
   this->VisitLabels(this->GetAllLabelValues(), searchName);
 
   return std::vector<std::string>(names.begin(), names.end());
 }
 
 std::vector<std::string> mitk::LabelSetImage::GetLabelClassNamesByGroup(GroupIndexType index) const
 {
   std::set<std::string> names;
   auto searchName = [&names](const Label* l) { names.emplace(l->GetName()); };
   this->VisitLabels(this->GetLabelValuesByGroup(index), searchName);
 
   return std::vector<std::string>(names.begin(), names.end());
 }
 
 void mitk::LabelSetImage::SetAllLabelsVisible(bool visible)
 {
   auto setVisibility = [visible](Label* l) { l->SetVisible(visible); };
 
   this->ApplyToLabels(this->GetAllLabelValues(), setVisibility);
 }
 
 void mitk::LabelSetImage::SetAllLabelsVisibleByGroup(GroupIndexType group, bool visible)
 {
   auto setVisibility = [visible](Label* l) { l->SetVisible(visible); };
 
   this->ApplyToLabels(this->GetLabelValuesByGroup(group), setVisibility);
 }
 
 void mitk::LabelSetImage::SetAllLabelsVisibleByName(GroupIndexType group, std::string_view name, bool visible)
 {
   auto setVisibility = [visible](Label* l) { l->SetVisible(visible); };
 
   this->ApplyToLabels(this->GetLabelValuesByName(group, name), setVisibility);
 }
 
 void mitk::LabelSetImage::SetAllLabelsLocked(bool locked)
 {
   auto setLock = [locked](Label* l) { l->SetLocked(locked); };
 
   this->ApplyToLabels(this->GetAllLabelValues(), setLock);
 }
 
 void mitk::LabelSetImage::SetAllLabelsLockedByGroup(GroupIndexType group, bool locked)
 {
   auto setLock = [locked](Label* l) { l->SetLocked(locked); };
 
   this->ApplyToLabels(this->GetLabelValuesByGroup(group), setLock);
 }
 
 void mitk::LabelSetImage::SetAllLabelsLockedByName(GroupIndexType group, std::string_view name, bool locked)
 {
   auto setLock = [locked](Label* l) { l->SetLocked(locked); };
 
   this->ApplyToLabels(this->GetLabelValuesByName(group, name), setLock);
 }
 
 bool mitk::Equal(const mitk::LabelSetImage &leftHandSide,
                  const mitk::LabelSetImage &rightHandSide,
                  ScalarType eps,
                  bool verbose)
 {
   bool returnValue = true;
 
   /* LabelSetImage members */
 
   MITK_INFO(verbose) << "--- LabelSetImage Equal ---";
 
   // m_LookupTable;
   const mitk::LookupTable* lhsLUT = leftHandSide.GetLookupTable();
   const mitk::LookupTable* rhsLUT = rightHandSide.GetLookupTable();
 
   returnValue = *lhsLUT == *rhsLUT;
   if (!returnValue)
   {
     MITK_INFO(verbose) << "Lookup tabels not equal.";
     return returnValue;
     ;
   }
 
   // number layers
   returnValue = leftHandSide.GetNumberOfLayers() == rightHandSide.GetNumberOfLayers();
   if (!returnValue)
   {
     MITK_INFO(verbose) << "Number of layers not equal.";
     return false;
   }
 
   // total number labels
   returnValue = leftHandSide.GetTotalNumberOfLabels() == rightHandSide.GetTotalNumberOfLabels();
   if (!returnValue)
   {
     MITK_INFO(verbose) << "Total number of labels not equal.";
     return false;
   }
 
   // active layer
   returnValue = leftHandSide.GetActiveLayer() == rightHandSide.GetActiveLayer();
   if (!returnValue)
   {
     MITK_INFO(verbose) << "Active layer not equal.";
     return false;
   }
 
   if (4 == leftHandSide.GetDimension())
   {
     MITK_INFO(verbose) << "Can not compare image data for 4D images - skipping check.";
   }
   else
   {
     // working image data
     returnValue = mitk::Equal((const mitk::Image &)leftHandSide, (const mitk::Image &)rightHandSide, eps, verbose);
     if (!returnValue)
     {
       MITK_INFO(verbose) << "Working image data not equal.";
       return false;
     }
   }
 
   if (leftHandSide.GetTotalNumberOfLabels() != rightHandSide.GetTotalNumberOfLabels())
   {
     MITK_INFO(verbose) << "Number of labels are not equal.";
     return false;
   }
 
   for (unsigned int layerIndex = 0; layerIndex < leftHandSide.GetNumberOfLayers(); layerIndex++)
   {
     if (4 == leftHandSide.GetDimension())
     {
       MITK_INFO(verbose) << "Can not compare image data for 4D images - skipping check.";
     }
     else
     {
       // layer image data
       returnValue =
         mitk::Equal(*leftHandSide.GetGroupImage(layerIndex), *rightHandSide.GetGroupImage(layerIndex), eps, verbose);
       if (!returnValue)
       {
         MITK_INFO(verbose) << "Layer image data not equal.";
         return false;
       }
     }
 
     // label data
     auto leftLabelsInGroup = leftHandSide.GetLabelValuesByGroup(layerIndex);
     auto rightLabelsInGroup = rightHandSide.GetLabelValuesByGroup(layerIndex);
 
     if (leftLabelsInGroup.size()!=rightLabelsInGroup.size())
     {
       MITK_INFO(verbose) << "Number of layer labels is not equal. Invalid layer:" <<layerIndex;
       return false;
     }
 
     for (ConstLabelVector::size_type index = 0; index < leftLabelsInGroup.size(); ++index)
     {
       if (!mitk::Equal(*(leftHandSide.GetLabel(leftLabelsInGroup[index])), *(rightHandSide.GetLabel(rightLabelsInGroup[index])),eps,verbose))
       {
         MITK_INFO(verbose) << "At least one label in layer is not equal. Invalid layer:" << layerIndex;
         return false;
       }
     }
   }
 
   return returnValue;
 }
 
 bool mitk::Equal(const mitk::LabelSetImage::ConstLabelVectorType& leftHandSide,
   const mitk::LabelSetImage::ConstLabelVectorType& rightHandSide, ScalarType eps, bool verbose)
 {
   bool returnValue = true;
 
   // container size;
   returnValue = leftHandSide.size() == rightHandSide.size();
   if (!returnValue)
   {
     MITK_INFO(verbose) << "Number of labels not equal.";
     return returnValue;
     ;
   }
 
   // m_LabelContainer;
   auto lhsit = leftHandSide.begin();
   auto rhsit = rightHandSide.begin();
   for (; lhsit != leftHandSide.end(); ++lhsit, ++rhsit)
   {
     returnValue = mitk::Equal(**rhsit, **lhsit,eps,verbose);
     if (!returnValue)
     {
       MITK_INFO(verbose) << "Label in label container not equal.";
       return returnValue;
       ;
     }
   }
 
   return returnValue;
 }
 
 /**Helper function to convert a vector of labels into a label map
  * @pre every label in the vector has a unique value.*/
 using ConstLabelMapType = std::map<mitk::LabelSetImage::LabelValueType, mitk::Label::ConstPointer>;
 ConstLabelMapType ConvertLabelVectorToMap(const mitk::ConstLabelVector& labelV)
 {
   ConstLabelMapType result;
   for (auto label : labelV)
   {
     const auto value = label->GetValue();
     auto finding = result.find(value);
     if (finding != result.end()) mitkThrow() << "Operation failed. Cannot convert label vector into label map, because at least one label value is not unique. Violating label value: " << value;
     result.insert(std::make_pair(value, label));
   }
 
   return result;
 }
 
 
 /** Functor class that implements the label transfer and is used in conjunction with the itk::BinaryFunctorImageFilter.
 * For details regarding the usage of the filter and the functor patterns, please see info of itk::BinaryFunctorImageFilter.
 */
 template <class TDestinationPixel, class TSourcePixel, class TOutputpixel>
 class LabelTransferFunctor
 {
 
 public:
   LabelTransferFunctor() {};
 
   LabelTransferFunctor(const ConstLabelMapType& destinationLabels, mitk::Label::PixelType sourceBackground,
     mitk::Label::PixelType destinationBackground, bool destinationBackgroundLocked,
     mitk::Label::PixelType sourceLabel, mitk::Label::PixelType newDestinationLabel, mitk::MultiLabelSegmentation::MergeStyle mergeStyle,
     mitk::MultiLabelSegmentation::OverwriteStyle overwriteStyle) :
     m_DestinationLabels(destinationLabels), m_SourceBackground(sourceBackground),
     m_DestinationBackground(destinationBackground), m_DestinationBackgroundLocked(destinationBackgroundLocked),
     m_SourceLabel(sourceLabel), m_NewDestinationLabel(newDestinationLabel), m_MergeStyle(mergeStyle), m_OverwriteStyle(overwriteStyle)
   {
   };
 
   ~LabelTransferFunctor() {};
 
   bool operator!=(const LabelTransferFunctor& other)const
   {
     return !(*this == other);
   }
   bool operator==(const LabelTransferFunctor& other) const
   {
     return this->m_SourceBackground == other.m_SourceBackground &&
       this->m_DestinationBackground == other.m_DestinationBackground &&
       this->m_DestinationBackgroundLocked == other.m_DestinationBackgroundLocked &&
       this->m_SourceLabel == other.m_SourceLabel &&
       this->m_NewDestinationLabel == other.m_NewDestinationLabel &&
       this->m_MergeStyle == other.m_MergeStyle &&
       this->m_OverwriteStyle == other.m_OverwriteStyle &&
       this->m_DestinationLabels == other.m_DestinationLabels;
   }
 
   LabelTransferFunctor& operator=(const LabelTransferFunctor& other)
   {
     this->m_DestinationLabels = other.m_DestinationLabels;
     this->m_SourceBackground = other.m_SourceBackground;
     this->m_DestinationBackground = other.m_DestinationBackground;
     this->m_DestinationBackgroundLocked = other.m_DestinationBackgroundLocked;
     this->m_SourceLabel = other.m_SourceLabel;
     this->m_NewDestinationLabel = other.m_NewDestinationLabel;
     this->m_MergeStyle = other.m_MergeStyle;
     this->m_OverwriteStyle = other.m_OverwriteStyle;
 
     return *this;
   }
 
   inline TOutputpixel operator()(const TDestinationPixel& existingDestinationValue, const TSourcePixel& existingSourceValue)
   {
     if (existingSourceValue == this->m_SourceLabel)
     {
       if (mitk::MultiLabelSegmentation::OverwriteStyle::IgnoreLocks == this->m_OverwriteStyle)
       {
         return this->m_NewDestinationLabel;
       }
       else
       {
         if (existingDestinationValue == m_DestinationBackground)
         {
           if (!m_DestinationBackgroundLocked)
           {
             return this->m_NewDestinationLabel;
           }
         }
         else
         {
           auto labelFinding = this->m_DestinationLabels.find(existingDestinationValue);
           if (labelFinding==this->m_DestinationLabels.end() || !labelFinding->second->GetLocked())
           {
             return this->m_NewDestinationLabel;
           }
         }
       }
     }
     else if (mitk::MultiLabelSegmentation::MergeStyle::Replace == this->m_MergeStyle
       && existingSourceValue == this->m_SourceBackground
       && existingDestinationValue == this->m_NewDestinationLabel
       && (mitk::MultiLabelSegmentation::OverwriteStyle::IgnoreLocks == this->m_OverwriteStyle
           || !this->m_DestinationBackgroundLocked))
     {
       return this->m_DestinationBackground;
     }
 
     return existingDestinationValue;
   }
 
 private:
   ConstLabelMapType m_DestinationLabels;
   mitk::Label::PixelType m_SourceBackground = 0;
   mitk::Label::PixelType m_DestinationBackground = 0;
   bool m_DestinationBackgroundLocked = false;
   mitk::Label::PixelType m_SourceLabel = 1;
   mitk::Label::PixelType m_NewDestinationLabel = 1;
   mitk::MultiLabelSegmentation::MergeStyle m_MergeStyle = mitk::MultiLabelSegmentation::MergeStyle::Replace;
   mitk::MultiLabelSegmentation::OverwriteStyle m_OverwriteStyle = mitk::MultiLabelSegmentation::OverwriteStyle::RegardLocks;
 };
 
 /**Helper function used by TransferLabelContentAtTimeStep to allow the templating over different image dimensions in conjunction of AccessFixedPixelTypeByItk_n.*/
 template<unsigned int VImageDimension>
 void TransferLabelContentAtTimeStepHelper(const itk::Image<mitk::Label::PixelType, VImageDimension>* itkSourceImage, mitk::Image* destinationImage,
   const mitk::ConstLabelVector& destinationLabels, mitk::Label::PixelType sourceBackground, mitk::Label::PixelType destinationBackground,
   bool destinationBackgroundLocked, mitk::Label::PixelType sourceLabel, mitk::Label::PixelType newDestinationLabel, mitk::MultiLabelSegmentation::MergeStyle mergeStyle, mitk::MultiLabelSegmentation::OverwriteStyle overwriteStyle)
 {
   typedef itk::Image<mitk::Label::PixelType, VImageDimension> ContentImageType;
   typename ContentImageType::Pointer itkDestinationImage;
   mitk::CastToItkImage(destinationImage, itkDestinationImage);
 
   auto sourceRegion = itkSourceImage->GetLargestPossibleRegion();
   auto relevantRegion = itkDestinationImage->GetLargestPossibleRegion();
   bool overlapping = relevantRegion.Crop(sourceRegion);
 
   if (!overlapping)
   {
     mitkThrow() << "Invalid call of TransferLabelContentAtTimeStep; sourceImage and destinationImage seem to have no overlapping image region.";
   }
 
   typedef LabelTransferFunctor <mitk::Label::PixelType, mitk::Label::PixelType, mitk::Label::PixelType> LabelTransferFunctorType;
   typedef itk::BinaryFunctorImageFilter<ContentImageType, ContentImageType, ContentImageType, LabelTransferFunctorType> FilterType;
 
   LabelTransferFunctorType transferFunctor(ConvertLabelVectorToMap(destinationLabels), sourceBackground, destinationBackground,
     destinationBackgroundLocked, sourceLabel, newDestinationLabel, mergeStyle, overwriteStyle);
 
   auto transferFilter = FilterType::New();
 
   transferFilter->SetFunctor(transferFunctor);
   transferFilter->InPlaceOn();
   transferFilter->SetInput1(itkDestinationImage);
   transferFilter->SetInput2(itkSourceImage);
   transferFilter->GetOutput()->SetRequestedRegion(relevantRegion);
 
   transferFilter->Update();
 }
 
 void mitk::TransferLabelContentAtTimeStep(
   const Image* sourceImage, Image* destinationImage, const mitk::ConstLabelVector& destinationLabels, const TimeStepType timeStep, mitk::Label::PixelType sourceBackground,
   mitk::Label::PixelType destinationBackground, bool destinationBackgroundLocked, LabelValueMappingVector labelMapping,
   MultiLabelSegmentation::MergeStyle mergeStyle, MultiLabelSegmentation::OverwriteStyle overwriteStlye)
 {
   if (nullptr == sourceImage)
   {
     mitkThrow() << "Invalid call of TransferLabelContentAtTimeStep; sourceImage must not be null.";
   }
   if (nullptr == destinationImage)
   {
     mitkThrow() << "Invalid call of TransferLabelContentAtTimeStep; destinationImage must not be null.";
   }
 
   if (sourceImage == destinationImage && labelMapping.size() > 1)
   {
     MITK_DEBUG << "Warning. Using TransferLabelContentAtTimeStep or TransferLabelContent with equal source and destination and more then on label to transfer, can lead to wrong results. Please see documentation and verify that the usage is OK.";
   }
 
   Image::ConstPointer sourceImageAtTimeStep = SelectImageByTimeStep(sourceImage, timeStep);
   Image::Pointer destinationImageAtTimeStep = SelectImageByTimeStep(destinationImage, timeStep);
 
   if (nullptr == sourceImageAtTimeStep)
   {
     mitkThrow() << "Invalid call of TransferLabelContentAtTimeStep; sourceImage does not have the requested time step: " << timeStep;
   }
   if (nullptr == destinationImageAtTimeStep)
   {
     mitkThrow() << "Invalid call of TransferLabelContentAtTimeStep; destinationImage does not have the requested time step: " << timeStep;
   }
 
   auto destLabelMap = ConvertLabelVectorToMap(destinationLabels);
   for (const auto& [sourceLabel, newDestinationLabel] : labelMapping)
   {
     if (LabelSetImage::UNLABELED_VALUE!=newDestinationLabel && destLabelMap.end() == destLabelMap.find(newDestinationLabel))
     {
       mitkThrow() << "Invalid call of TransferLabelContentAtTimeStep. Defined destination label does not exist in destinationImage. newDestinationLabel: " << newDestinationLabel;
     }
 
     AccessFixedPixelTypeByItk_n(sourceImageAtTimeStep, TransferLabelContentAtTimeStepHelper, (Label::PixelType), (destinationImageAtTimeStep, destinationLabels, sourceBackground, destinationBackground, destinationBackgroundLocked, sourceLabel, newDestinationLabel, mergeStyle, overwriteStlye));
   }
   destinationImage->Modified();
 }
 
 void mitk::TransferLabelContent(
   const Image* sourceImage, Image* destinationImage, const mitk::ConstLabelVector& destinationLabels, mitk::Label::PixelType sourceBackground,
   mitk::Label::PixelType destinationBackground, bool destinationBackgroundLocked, LabelValueMappingVector labelMapping,
   MultiLabelSegmentation::MergeStyle mergeStyle, MultiLabelSegmentation::OverwriteStyle overwriteStlye)
 {
   if (nullptr == sourceImage)
   {
     mitkThrow() << "Invalid call of TransferLabelContent; sourceImage must not be null.";
   }
   if (nullptr == destinationImage)
   {
     mitkThrow() << "Invalid call of TransferLabelContent; destinationImage must not be null.";
   }
 
   const auto sourceTimeStepCount = sourceImage->GetTimeGeometry()->CountTimeSteps();
   if (sourceTimeStepCount != destinationImage->GetTimeGeometry()->CountTimeSteps())
   {
     mitkThrow() << "Invalid call of TransferLabelContent; mismatch between images in number of time steps.";
   }
 
   for (mitk::TimeStepType i = 0; i < sourceTimeStepCount; ++i)
   {
     TransferLabelContentAtTimeStep(sourceImage, destinationImage, destinationLabels, i, sourceBackground,
       destinationBackground, destinationBackgroundLocked, labelMapping, mergeStyle, overwriteStlye);
   }
 }
 
 void mitk::TransferLabelContentAtTimeStep(
   const LabelSetImage* sourceImage, LabelSetImage* destinationImage, const TimeStepType timeStep,
   LabelValueMappingVector labelMapping,
   MultiLabelSegmentation::MergeStyle mergeStyle, MultiLabelSegmentation::OverwriteStyle overwriteStlye)
 {
   if (nullptr == sourceImage)
   {
     mitkThrow() << "Invalid call of TransferLabelContentAtTimeStep; sourceImage must not be null.";
   }
 
   auto destinationLabels = destinationImage->GetConstLabelsByValue(destinationImage->GetLabelValuesByGroup(destinationImage->GetActiveLayer()));
 
   for (const auto& mappingElement : labelMapping)
   {
     if (LabelSetImage::UNLABELED_VALUE != mappingElement.first && !sourceImage->ExistLabel(mappingElement.first, sourceImage->GetActiveLayer()))
     {
       mitkThrow() << "Invalid call of TransferLabelContentAtTimeStep. Defined source label does not exist in sourceImage. SourceLabel: " << mappingElement.first;
     }
   }
 
   TransferLabelContentAtTimeStep(sourceImage, destinationImage, destinationLabels, timeStep, LabelSetImage::UNLABELED_VALUE, LabelSetImage::UNLABELED_VALUE, destinationImage->GetUnlabeledLabelLock(),
     labelMapping, mergeStyle, overwriteStlye);
 }
 
 void mitk::TransferLabelContent(
   const LabelSetImage* sourceImage, LabelSetImage* destinationImage,
   LabelValueMappingVector labelMapping,
   MultiLabelSegmentation::MergeStyle mergeStyle, MultiLabelSegmentation::OverwriteStyle overwriteStlye)
 {
   if (nullptr == sourceImage)
   {
     mitkThrow() << "Invalid call of TransferLabelContent; sourceImage must not be null.";
   }
   if (nullptr == destinationImage)
   {
     mitkThrow() << "Invalid call of TransferLabelContent; destinationImage must not be null.";
   }
 
   const auto sourceTimeStepCount = sourceImage->GetTimeGeometry()->CountTimeSteps();
   if (sourceTimeStepCount != destinationImage->GetTimeGeometry()->CountTimeSteps())
   {
     mitkThrow() << "Invalid call of TransferLabelContent; images have no equal number of time steps.";
   }
 
   for (mitk::TimeStepType i = 0; i < sourceTimeStepCount; ++i)
   {
     TransferLabelContentAtTimeStep(sourceImage, destinationImage, i, labelMapping, mergeStyle, overwriteStlye);
   }
 }
 
diff --git a/Modules/SurfaceInterpolation/mitkSurfaceInterpolationController.cpp b/Modules/SurfaceInterpolation/mitkSurfaceInterpolationController.cpp
index 07e66c19f7..9e534ddc76 100644
--- a/Modules/SurfaceInterpolation/mitkSurfaceInterpolationController.cpp
+++ b/Modules/SurfaceInterpolation/mitkSurfaceInterpolationController.cpp
@@ -1,883 +1,876 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include <mitkSurfaceInterpolationController.h>
 
 #include <shared_mutex>
 
 #include <mitkCreateDistanceImageFromSurfaceFilter.h>
 #include <mitkComputeContourSetNormalsFilter.h>
 #include <mitkImageAccessByItk.h>
-#include <mitkImagePixelReadAccessor.h>
 #include <mitkImageTimeSelector.h>
 #include <mitkImageToSurfaceFilter.h>
-#include <mitkLabelSetImage.h>
-#include <mitkMemoryUtilities.h>
 #include <mitkNodePredicateDataUID.h>
 #include <mitkNodePredicateProperty.h>
 #include <mitkNodePredicateAnd.h>
 #include <mitkPlanarCircle.h>
 #include <mitkPlaneGeometry.h>
 #include <mitkReduceContourSetFilter.h>
 
-#include <vtkFieldData.h>
-#include <vtkMath.h>
-#include <vtkPolygon.h>
-
 struct CPICache
 {
   mitk::SurfaceInterpolationController::CPIVector cpis;
   itk::TimeStamp cpiTimeStamp;
   mitk::Surface::Pointer cachedSurface;
 };
 
 typedef std::map<mitk::TimeStepType, CPICache> CPITimeStepMap;
 typedef std::map<mitk::LabelSetImage::LabelValueType, CPITimeStepMap> CPITimeStepLabelMap;
 
 typedef std::map<const mitk::LabelSetImage*, CPITimeStepLabelMap> CPITimeStepLabelSegMap;
 
 CPITimeStepLabelSegMap cpiMap;
 std::shared_mutex cpiMutex;
 
 std::map<mitk::LabelSetImage*, unsigned long> segmentationObserverTags;
 std::map<mitk::LabelSetImage*, unsigned long> labelRemovedObserverTags;
 
 mitk::SurfaceInterpolationController::SurfaceInterpolationController()
   : m_DistanceImageVolume(50000),
     m_SelectedSegmentation(nullptr)
 {
 }
 
 mitk::SurfaceInterpolationController::~SurfaceInterpolationController()
 {
   this->RemoveObservers();
 }
 
 void mitk::SurfaceInterpolationController::RemoveObservers()
 {
   // Removing all observers
   while (segmentationObserverTags.size())
   {
     this->RemoveObserversInternal(segmentationObserverTags.begin()->first);
   }
 }
 
 mitk::SurfaceInterpolationController *mitk::SurfaceInterpolationController::GetInstance()
 {
   static mitk::SurfaceInterpolationController::Pointer m_Instance;
 
   if (m_Instance.IsNull())
   {
     m_Instance = SurfaceInterpolationController::New();
   }
   return m_Instance;
 }
 
 void mitk::SurfaceInterpolationController::AddNewContours(const std::vector<ContourPositionInformation>& newCPIs,
   bool reinitializationAction, bool silent)
 {
   auto selectedSegmentation = m_SelectedSegmentation.Lock();
   if (selectedSegmentation.IsNull()) return;
 
   for (auto cpi : newCPIs)
   {
     if (cpi.Contour->GetVtkPolyData()->GetNumberOfPoints() > 0)
     {
       this->AddToCPIMap(cpi, reinitializationAction);
     }
   }
   if (!silent) this->Modified();
 }
 
 
 mitk::DataNode* GetSegmentationImageNodeInternal(mitk::DataStorage* ds, const mitk::LabelSetImage* seg)
 {
   if (nullptr == ds) return nullptr;
   if (nullptr == seg) return nullptr;
 
   mitk::DataNode* segmentationNode = nullptr;
   mitk::NodePredicateDataUID::Pointer dataUIDPredicate = mitk::NodePredicateDataUID::New(seg->GetUID());
   auto dataNodeObjects = ds->GetSubset(dataUIDPredicate);
 
   if (dataNodeObjects->Size() != 0)
   {
     for (auto it = dataNodeObjects->Begin(); it != dataNodeObjects->End(); ++it)
     {
       segmentationNode = it->Value();
     }
   }
   else
   {
     MITK_ERROR << "Unable to find the labelSetImage with the desired UID.";
   }
   return segmentationNode;
 }
 
 mitk::DataNode* mitk::SurfaceInterpolationController::GetSegmentationImageNode() const
 {
   if (m_DataStorage.IsNull()) return nullptr;
   auto selectedSegmentation = m_SelectedSegmentation.Lock();
   if (selectedSegmentation.IsNull()) return nullptr;
   return GetSegmentationImageNodeInternal(this->m_DataStorage, selectedSegmentation);
 }
 
 mitk::DataStorage::SetOfObjects::ConstPointer mitk::SurfaceInterpolationController::GetPlaneGeometryNodeFromDataStorage(const DataNode* segNode, LabelSetImage::LabelValueType labelValue, TimeStepType timeStep) const
 {
   DataStorage::SetOfObjects::Pointer relevantNodes = DataStorage::SetOfObjects::New();
 
   if (m_DataStorage.IsNotNull())
   {
     //remove relevant plane nodes
     auto nodes = this->GetPlaneGeometryNodeFromDataStorage(segNode, labelValue);
 
     for (auto it = nodes->Begin(); it != nodes->End(); ++it)
     {
       auto aTS = dynamic_cast<mitk::IntProperty*>(it->Value()->GetProperty("timeStep"))->GetValue();
       bool sameTS = (timeStep == aTS);
 
       if (sameTS)
       {
         relevantNodes->push_back(it->Value());
       }
     }
   }
   return relevantNodes;
 }
 
 mitk::DataStorage::SetOfObjects::ConstPointer mitk::SurfaceInterpolationController::GetPlaneGeometryNodeFromDataStorage(const DataNode* segNode, LabelSetImage::LabelValueType labelValue) const
 {
   auto isContourPlaneGeometry = NodePredicateProperty::New("isContourPlaneGeometry", mitk::BoolProperty::New(true));
   auto isCorrectLabel = NodePredicateProperty::New("labelID", mitk::UShortProperty::New(labelValue));
   auto searchPredicate = NodePredicateAnd::New(isContourPlaneGeometry, isCorrectLabel);
 
   mitk::DataStorage::SetOfObjects::ConstPointer result;
   if (m_DataStorage.IsNotNull()) result = m_DataStorage->GetDerivations(segNode, searchPredicate);
   return result;
 }
 
 mitk::DataStorage::SetOfObjects::ConstPointer mitk::SurfaceInterpolationController::GetPlaneGeometryNodeFromDataStorage(const DataNode* segNode) const
 {
   auto isContourPlaneGeometry = NodePredicateProperty::New("isContourPlaneGeometry", mitk::BoolProperty::New(true));
 
   mitk::DataStorage::SetOfObjects::ConstPointer result;
   if (m_DataStorage.IsNotNull()) result = m_DataStorage->GetDerivations(segNode, isContourPlaneGeometry);
   return result;
 }
 void mitk::SurfaceInterpolationController::AddPlaneGeometryNodeToDataStorage(const ContourPositionInformation& contourInfo) const
 {
   auto selectedSegmentation = m_SelectedSegmentation.Lock();
   if (selectedSegmentation.IsNull())
   {
     mitkThrow()<< "Cannot add plane geometries. No valid segmentation selected.";
   }
 
   if (!selectedSegmentation->GetTimeGeometry()->IsValidTimeStep(contourInfo.TimeStep))
   {
     MITK_ERROR << "Invalid time point requested in AddPlaneGeometryNodeToDataStorage.";
     return;
   }
 
   if (m_DataStorage.IsNull())
   {
     MITK_DEBUG << "Cannot add plane geometry nodes. No data storage is set.";
     return;
   }
 
   auto planeGeometry = contourInfo.Plane;
   if (planeGeometry)
   {
     auto segmentationNode = this->GetSegmentationImageNode();
     mitk::DataStorage::SetOfObjects::ConstPointer contourNodes = this->GetPlaneGeometryNodeFromDataStorage(segmentationNode, contourInfo.LabelValue, contourInfo.TimeStep);
 
     mitk::DataNode::Pointer contourPlaneGeometryDataNode;
 
     //  Go through the pre-existing contours and check if the contour position matches them.
     for (auto it = contourNodes->Begin(); it != contourNodes->End(); ++it)
     {
       auto planeData = dynamic_cast<mitk::PlanarFigure*>(it->Value()->GetData());
       if (nullptr == planeData) mitkThrow() << "Invalid ContourPlaneGeometry data node. Does not contion a planar figure as data.";
 
       bool samePlane = contourInfo.Plane->IsOnPlane(planeData->GetPlaneGeometry());
 
       if (samePlane)
       {
         contourPlaneGeometryDataNode = it->Value();
         break;
       }
     }
 
     //  Go through the contourPlaneGeometry Data and add the segmentationNode to it.
     if (contourPlaneGeometryDataNode.IsNull())
     {
       auto planeGeometryData = mitk::PlanarCircle::New();
       planeGeometryData->SetPlaneGeometry(planeGeometry->Clone());
       mitk::Point2D p1;
       planeGeometry->Map(planeGeometry->GetCenter(), p1);
       planeGeometryData->PlaceFigure(p1);
       planeGeometryData->SetCurrentControlPoint(p1);
       planeGeometryData->SetProperty("initiallyplaced", mitk::BoolProperty::New(true));
 
       std::string contourName = "contourPlane L " + std::to_string(contourInfo.LabelValue) + " T " + std::to_string(contourInfo.TimeStep);
 
       contourPlaneGeometryDataNode = mitk::DataNode::New();
       contourPlaneGeometryDataNode->SetData(planeGeometryData);
 
       //  No need to change properties
       contourPlaneGeometryDataNode->SetProperty("helper object", mitk::BoolProperty::New(false));
       contourPlaneGeometryDataNode->SetProperty("hidden object", mitk::BoolProperty::New(true));
       contourPlaneGeometryDataNode->SetProperty("isContourPlaneGeometry", mitk::BoolProperty::New(true));
       contourPlaneGeometryDataNode->SetVisibility(false);
 
       //  Need to change properties
       contourPlaneGeometryDataNode->SetProperty("name", mitk::StringProperty::New(contourName) );
       contourPlaneGeometryDataNode->SetProperty("labelID", mitk::UShortProperty::New(contourInfo.LabelValue));
       contourPlaneGeometryDataNode->SetProperty("timeStep", mitk::IntProperty::New(contourInfo.TimeStep));
 
       contourPlaneGeometryDataNode->SetData(planeGeometryData);
 
       m_DataStorage->Add(contourPlaneGeometryDataNode, segmentationNode);
     }
   }
 }
 
 void mitk::SurfaceInterpolationController::AddToCPIMap(ContourPositionInformation& contourInfo, bool reinitializationAction)
 {
   auto selectedSegmentation = m_SelectedSegmentation.Lock();
   if (selectedSegmentation.IsNull())
     return;
 
   if (!selectedSegmentation->GetTimeGeometry()->IsValidTimeStep(contourInfo.TimeStep))
   {
     MITK_ERROR << "Invalid time step requested for interpolation pipeline.";
     return;
   }
 
   if (contourInfo.Plane == nullptr)
   {
     MITK_ERROR << "contourInfo plane is null.";
     return;
   }
 
   if (contourInfo.Contour->GetVtkPolyData()->GetNumberOfPoints() == 0)
   {
     this->RemoveContour(contourInfo);
     MITK_DEBUG << "contourInfo contour is empty.";
     return;
   }
 
   {
     std::lock_guard<std::shared_mutex> guard(cpiMutex);
     const auto& currentTimeStep = contourInfo.TimeStep;
     const auto& currentLabelValue = contourInfo.LabelValue;
 
     auto& currentImageContours = cpiMap[selectedSegmentation];
     auto& currentLabelContours = currentImageContours[currentLabelValue];
     auto& currentCPICache = currentLabelContours[currentTimeStep];
     auto& currentContourList = currentCPICache.cpis;
 
     auto finding = std::find_if(currentContourList.begin(), currentContourList.end(), [contourInfo](const ContourPositionInformation& element) {return contourInfo.Plane->IsOnPlane(element.Plane); });
 
     if (finding != currentContourList.end())
     {
       MITK_DEBUG << "CPI already exists. CPI is updated. Label: "<< currentLabelValue << "; Time Step: " << currentTimeStep;
       *finding = contourInfo;
     }
     else
     {
       currentContourList.push_back(contourInfo);
     }
     currentCPICache.cpiTimeStamp.Modified();
   }
 
   if (!reinitializationAction)
   {
     this->AddPlaneGeometryNodeToDataStorage(contourInfo);
   }
 }
 
 bool mitk::SurfaceInterpolationController::RemoveContour(ContourPositionInformation contourInfo, bool keepPlaceholderForUndo)
 {
   auto selectedSegmentation = m_SelectedSegmentation.Lock();
   if (selectedSegmentation.IsNull())
   {
     return false;
   }
 
   if (!selectedSegmentation->GetTimeGeometry()->IsValidTimeStep(contourInfo.TimeStep))
   {
     return false;
   }
 
   bool removedIt = false;
 
   {
     std::lock_guard<std::shared_mutex> cpiGuard(cpiMutex);
 
     const auto currentTimeStep = contourInfo.TimeStep;
     const auto currentLabel = contourInfo.LabelValue;
     auto& cpiCache = cpiMap.at(selectedSegmentation).at(currentLabel).at(currentTimeStep);
     auto it = cpiCache.cpis.begin();
 
 
     while (it != cpiCache.cpis.end())
     {
       const ContourPositionInformation& currentContour = (*it);
       if (currentContour.Plane->IsOnPlane(contourInfo.Plane))
       {
         if (keepPlaceholderForUndo)
         {
           it->Contour = nullptr;
         }
         else
         {
           cpiCache.cpis.erase(it);
         }
         cpiCache.cpiTimeStamp.Modified();
         removedIt = true;
 
         if (m_DataStorage.IsNotNull())
         {
           mitk::DataNode::Pointer contourPlaneGeometryDataNode;
 
           auto contourNodes = this->GetPlaneGeometryNodeFromDataStorage(GetSegmentationImageNodeInternal(m_DataStorage, selectedSegmentation), currentLabel, currentTimeStep);
 
           //  Go through the nodes and check if the contour position matches them.
           for (auto it = contourNodes->Begin(); it != contourNodes->End(); ++it)
           {
             auto planeData = dynamic_cast<mitk::PlanarFigure*>(it->Value()->GetData());
             if (nullptr == planeData) mitkThrow() << "Invalid ContourPlaneGeometry data node. Does not contion a planar figure as data.";
 
             bool samePlane = contourInfo.Plane->IsOnPlane(planeData->GetPlaneGeometry());
 
             if (samePlane)
             {
               m_DataStorage->Remove(it->Value());
               break;
             }
           }
         }
         break;
       }
       ++it;
     }
   }
 
   return removedIt;
 }
 
 void mitk::SurfaceInterpolationController::AddActiveLabelContoursForInterpolation(ReduceContourSetFilter* reduceFilter, const LabelSetImage* segmentationImage, LabelSetImage::LabelValueType labelValue, TimeStepType timeStep)
 {
   const auto& currentImageContours = cpiMap.at(segmentationImage);
 
   auto finding = currentImageContours.find(labelValue);
   if (finding == currentImageContours.end())
   {
     MITK_INFO << "Contours for label don't exist. Label value: " << labelValue;
     return;
   }
 
   const auto& currentLabelContoursMap = finding->second;
 
   auto tsfinding = currentLabelContoursMap.find(timeStep);
   if (tsfinding == currentLabelContoursMap.end())
   {
     MITK_INFO << "Contours for current time step don't exist.";
     return;
   }
 
   const auto& currentContours = tsfinding->second.cpis;
 
   unsigned int index = 0;
   for (const auto&  cpi : currentContours)
   {
     if (!cpi.IsPlaceHolder())
     {
       reduceFilter->SetInput(index, cpi.Contour);
       ++index;
     }
   }
 }
 
 bool CPICacheIsOutdated(const mitk::LabelSetImage* segmentationImage, mitk::LabelSetImage::LabelValueType labelValue, mitk::TimeStepType timeStep)
 {
   const auto& currentImageContours = cpiMap.at(segmentationImage);
 
   auto finding = currentImageContours.find(labelValue);
   if (finding == currentImageContours.end())
   {
     return false;
   }
 
   const auto& currentLabelContoursMap = finding->second;
 
   auto tsfinding = currentLabelContoursMap.find(timeStep);
   if (tsfinding == currentLabelContoursMap.end())
   {
     return false;
   }
 
   bool result = tsfinding->second.cachedSurface.IsNull() || tsfinding->second.cachedSurface->GetMTime() < tsfinding->second.cpiTimeStamp.GetMTime();
   return result;
 }
 
 void SetCPICacheSurface(mitk::Surface* surface, const mitk::LabelSetImage* segmentationImage, mitk::LabelSetImage::LabelValueType labelValue, mitk::TimeStepType timeStep)
 {
   const auto& currentImageContours = cpiMap.at(segmentationImage);
 
   auto finding = currentImageContours.find(labelValue);
   if (finding == currentImageContours.end())
   {
     return;
   }
 
   const auto& currentLabelContoursMap = finding->second;
 
   auto tsfinding = currentLabelContoursMap.find(timeStep);
   if (tsfinding == currentLabelContoursMap.end())
   {
     return;
   }
 
   cpiMap[segmentationImage][labelValue][timeStep].cachedSurface = surface;
 }
 
 void mitk::SurfaceInterpolationController::Interpolate(const LabelSetImage* segmentationImage, LabelSetImage::LabelValueType labelValue, TimeStepType timeStep)
 {
   if (nullptr == segmentationImage)
   {
     mitkThrow() << "Cannot interpolate contours. No valid segmentation passed.";
   }
 
   std::lock_guard<std::shared_mutex> guard(cpiMutex);
   auto it = cpiMap.find(segmentationImage);
   if (it == cpiMap.end())
   {
     mitkThrow() << "Cannot interpolate contours. Passed segmentation is not registered at controller.";
   }
 
   if (!segmentationImage->ExistLabel(labelValue))
   {
     mitkThrow() << "Cannot interpolate contours. None existant label request. Invalid label:" << labelValue;
   }
 
   if (!segmentationImage->GetTimeGeometry()->IsValidTimeStep(timeStep))
   {
     mitkThrow() << "Cannot interpolate contours. No valid time step requested. Invalid time step:" << timeStep;
   }
 
   if (!CPICacheIsOutdated(segmentationImage, labelValue, timeStep)) return;
 
   mitk::Surface::Pointer interpolationResult = nullptr;
 
   auto reduceFilter = ReduceContourSetFilter::New();
   auto normalsFilter = ComputeContourSetNormalsFilter::New();
   auto interpolateSurfaceFilter = CreateDistanceImageFromSurfaceFilter::New();
 
   const auto spacing = segmentationImage->GetGeometry(timeStep)->GetSpacing();
   double minSpacing = 100;
   double maxSpacing = 0;
   for (int i = 0; i < 3; i++)
   {
     if (spacing[i] < minSpacing)
     {
       minSpacing = spacing[i];
     }
     if (spacing[i] > maxSpacing)
     {
       maxSpacing = spacing[i];
     }
   }
   reduceFilter->SetMinSpacing(minSpacing);
   reduceFilter->SetMaxSpacing(maxSpacing);
   normalsFilter->SetMaxSpacing(maxSpacing);
   interpolateSurfaceFilter->SetDistanceImageVolume(m_DistanceImageVolume);
 
   reduceFilter->SetUseProgressBar(false);
   normalsFilter->SetUseProgressBar(true);
   normalsFilter->SetProgressStepSize(1);
   interpolateSurfaceFilter->SetUseProgressBar(true);
   interpolateSurfaceFilter->SetProgressStepSize(7);
 
   //  Set reference image for interpolation surface filter
   itk::ImageBase<3>::Pointer itkImage = itk::ImageBase<3>::New();
   mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New();
   timeSelector->SetInput(segmentationImage);
   timeSelector->SetTimeNr(timeStep);
   timeSelector->SetChannelNr(0);
   timeSelector->Update();
   mitk::Image::Pointer refSegImage = timeSelector->GetOutput();
   AccessFixedDimensionByItk_1(refSegImage, GetImageBase, 3, itkImage);
   interpolateSurfaceFilter->SetReferenceImage(itkImage.GetPointer());
 
   try
   {
     this->AddActiveLabelContoursForInterpolation(reduceFilter, segmentationImage, labelValue, timeStep);
     reduceFilter->Update();
     auto currentNumberOfReducedContours = reduceFilter->GetNumberOfOutputs();
 
     if (currentNumberOfReducedContours < 2)
     {
       // If no interpolation is possible reset the interpolation result
       MITK_INFO << "Interpolation impossible: not enough contours.";
     }
     else
     {
       normalsFilter->SetSegmentationBinaryImage(refSegImage);
 
       for (size_t i = 0; i < currentNumberOfReducedContours; ++i)
       {
         mitk::Surface::Pointer reducedContour = reduceFilter->GetOutput(i);
         reducedContour->DisconnectPipeline();
         normalsFilter->SetInput(i, reducedContour);
         interpolateSurfaceFilter->SetInput(i, normalsFilter->GetOutput(i));
       }
 
       // Setting up progress bar
       mitk::ProgressBar::GetInstance()->AddStepsToDo(10);
 
       // create a surface from the distance-image
       auto imageToSurfaceFilter = mitk::ImageToSurfaceFilter::New();
       imageToSurfaceFilter->SetInput(interpolateSurfaceFilter->GetOutput());
       imageToSurfaceFilter->SetThreshold(0);
       imageToSurfaceFilter->SetSmooth(true);
       imageToSurfaceFilter->SetSmoothIteration(1);
       imageToSurfaceFilter->Update();
 
       interpolationResult = mitk::Surface::New();
       interpolationResult->Expand(segmentationImage->GetTimeSteps());
 
       auto geometry = segmentationImage->GetTimeGeometry()->Clone();
       geometry->ReplaceTimeStepGeometries(mitk::Geometry3D::New());
       interpolationResult->SetTimeGeometry(geometry);
 
       interpolationResult->SetVtkPolyData(imageToSurfaceFilter->GetOutput()->GetVtkPolyData(), timeStep);
       interpolationResult->DisconnectPipeline();
 
       // Last progress step
       mitk::ProgressBar::GetInstance()->Progress(20);
 
     }
   }
   catch (const Exception& e)
   {
     MITK_ERROR << "Interpolation failed: " << e.what();
     interpolationResult = nullptr;
   }
 
   SetCPICacheSurface(interpolationResult, segmentationImage, labelValue, timeStep);
 }
 
 mitk::Surface::Pointer mitk::SurfaceInterpolationController::GetInterpolationResult(const LabelSetImage* segmentationImage, LabelSetImage::LabelValueType labelValue, TimeStepType timeStep)
 {
   if (nullptr == segmentationImage)
   {
     mitkThrow() << "Cannot interpolate contours. No valid segmentation passed.";
   }
 
   std::shared_lock<std::shared_mutex> guard(cpiMutex);
 
   if (cpiMap.find(segmentationImage) == cpiMap.end())
   {
     mitkThrow() << "Cannot interpolate contours. Passed segmentation is not registered at controller.";
   }
 
   if (!segmentationImage->ExistLabel(labelValue))
   {
     mitkThrow() << "Cannot interpolate contours. None existant label request. Invalid label:" << labelValue;
   }
 
   if (!segmentationImage->GetTimeGeometry()->IsValidTimeStep(timeStep))
   {
     mitkThrow() << "Cannot interpolate contours. No valid time step requested. Invalid time step:" << timeStep;
   }
 
   const auto& currentImageContours = cpiMap.at(segmentationImage);
 
   auto finding = currentImageContours.find(labelValue);
   if (finding == currentImageContours.end())
   {
     return nullptr;
   }
 
   const auto& currentLabelContoursMap = finding->second;
 
   auto tsfinding = currentLabelContoursMap.find(timeStep);
   if (tsfinding == currentLabelContoursMap.end())
   {
     return nullptr;
   }
 
   return tsfinding->second.cachedSurface;
 }
 
 void mitk::SurfaceInterpolationController::SetDataStorage(DataStorage::Pointer ds)
 {
   m_DataStorage = ds;
 }
 
 void mitk::SurfaceInterpolationController::SetDistanceImageVolume(unsigned int distImgVolume)
 {
   m_DistanceImageVolume = distImgVolume;
 }
 
 mitk::LabelSetImage* mitk::SurfaceInterpolationController::GetCurrentSegmentation()
 {
   return m_SelectedSegmentation.Lock();
 }
 
 unsigned int mitk::SurfaceInterpolationController::GetNumberOfInterpolationSessions()
 {
   return cpiMap.size();
 }
 
 template <typename TPixel, unsigned int VImageDimension>
 void mitk::SurfaceInterpolationController::GetImageBase(itk::Image<TPixel, VImageDimension> *input,
                                                         itk::ImageBase<3>::Pointer &result)
 {
   result->Graft(input);
 }
 
 void mitk::SurfaceInterpolationController::SetCurrentInterpolationSession(mitk::LabelSetImage* currentSegmentationImage)
 {
   auto selectedSegmentation = m_SelectedSegmentation.Lock();
 
   if (currentSegmentationImage == selectedSegmentation)
   {
     return;
   }
 
   m_SelectedSegmentation = currentSegmentationImage;
   selectedSegmentation = m_SelectedSegmentation.Lock();
 
   if (selectedSegmentation.IsNotNull())
   {
     std::lock_guard<std::shared_mutex> guard(cpiMutex);
 
     auto it = cpiMap.find(selectedSegmentation);
     if (it == cpiMap.end())
     {
       cpiMap[selectedSegmentation] = CPITimeStepLabelMap();
 
       auto command = itk::MemberCommand<SurfaceInterpolationController>::New();
       command->SetCallbackFunction(this, &SurfaceInterpolationController::OnSegmentationDeleted);
       segmentationObserverTags[selectedSegmentation] = selectedSegmentation->AddObserver(itk::DeleteEvent(), command);
       auto& controller = *this;
       const auto sender = selectedSegmentation.GetPointer();
       labelRemovedObserverTags[selectedSegmentation] = selectedSegmentation->AddObserver(mitk::LabelRemovedEvent(), [&controller, sender](const itk::EventObject& event)
         {
           controller.OnRemoveLabel(sender, event);
         });
     }
   }
 }
 
 void mitk::SurfaceInterpolationController::RemoveInterpolationSession(const mitk::LabelSetImage* segmentationImage)
 {
   if (nullptr != segmentationImage)
   {
     auto selectedSegmentation = m_SelectedSegmentation.Lock();
     if (selectedSegmentation == segmentationImage)
     {
       this->SetCurrentInterpolationSession(nullptr);
     }
 
     {
       std::lock_guard<std::shared_mutex> guard(cpiMutex);
       this->RemoveObserversInternal(segmentationImage);
       cpiMap.erase(segmentationImage);
       if (m_DataStorage.IsNotNull())
       {
         auto nodes = this->GetPlaneGeometryNodeFromDataStorage(GetSegmentationImageNodeInternal(this->m_DataStorage, segmentationImage));
         this->m_DataStorage->Remove(nodes);
       }
     }
 
   }
 }
 
 void mitk::SurfaceInterpolationController::RemoveObserversInternal(const mitk::LabelSetImage* segmentationImage)
 {
   auto pos = segmentationObserverTags.find(const_cast<mitk::LabelSetImage*>(segmentationImage));
   if (pos != segmentationObserverTags.end())
   {
     pos->first->RemoveObserver((*pos).second);
     segmentationObserverTags.erase(const_cast<mitk::LabelSetImage*>(segmentationImage));
   }
 
   auto pos2 = labelRemovedObserverTags.find(const_cast<mitk::LabelSetImage*>(segmentationImage));
   if (pos2 != labelRemovedObserverTags.end())
   {
     pos2->first->RemoveObserver((*pos2).second);
     labelRemovedObserverTags.erase(const_cast<mitk::LabelSetImage*>(segmentationImage));
   }
 }
 
 void mitk::SurfaceInterpolationController::RemoveAllInterpolationSessions()
 {
   while (!cpiMap.empty())
   {
     this->RemoveInterpolationSession(cpiMap.begin()->first);
   }
 }
 
 void mitk::SurfaceInterpolationController::RemoveContours(const LabelSetImage* segmentationImage,
   mitk::Label::PixelType label,
   TimeStepType timeStep)
 {
   if (nullptr == segmentationImage)
   {
     mitkThrow() << "Cannot remove contours. No valid segmentation passed.";
   }
 
   std::lock_guard<std::shared_mutex> guard(cpiMutex);
 
   auto segfinding = cpiMap.find(segmentationImage);
 
   if (segfinding != cpiMap.end())
   {
     auto& cpiLabelMap = cpiMap[segmentationImage];
     auto finding = cpiLabelMap.find(label);
 
     if (finding != cpiLabelMap.end())
     {
       cpiLabelMap[label].erase(timeStep);
     }
 
     if (m_DataStorage.IsNotNull())
     {
       //remove relevant plane nodes
       auto nodes = this->GetPlaneGeometryNodeFromDataStorage(GetSegmentationImageNodeInternal(this->m_DataStorage, segmentationImage), label, timeStep);
 
       this->m_DataStorage->Remove(nodes);
     }
     this->Modified();
   }
 }
 
 void mitk::SurfaceInterpolationController::RemoveContours(const LabelSetImage* segmentationImage,
   mitk::Label::PixelType label)
 {
   if (nullptr == segmentationImage)
   {
     mitkThrow() << "Cannot remove contours. No valid segmentation passed.";
   }
 
   std::lock_guard<std::shared_mutex> guard(cpiMutex);
 
   auto finding = cpiMap.find(segmentationImage);
   if (finding != cpiMap.end())
   {
     cpiMap[segmentationImage].erase(label);
 
     if (m_DataStorage.IsNotNull())
     {
       //remove relevant plane nodes
       auto nodes = this->GetPlaneGeometryNodeFromDataStorage(GetSegmentationImageNodeInternal(this->m_DataStorage, segmentationImage), label);
       this->m_DataStorage->Remove(nodes);
     }
     this->Modified();
   }
 }
 
 
 void mitk::SurfaceInterpolationController::OnSegmentationDeleted(const itk::Object *caller,
                                                                  const itk::EventObject & /*event*/)
 {
   auto tempImage = dynamic_cast<mitk::LabelSetImage *>(const_cast<itk::Object *>(caller));
   if (tempImage)
   {
     this->RemoveInterpolationSession(tempImage);
   }
 }
 
 void mitk::SurfaceInterpolationController::OnRemoveLabel(const itk::Object* caller, const itk::EventObject& event)
 {
   auto sendingSegmentation = dynamic_cast<const LabelSetImage*>(caller);
 
   auto removeEvent = dynamic_cast<const mitk::LabelRemovedEvent*>(&event);
 
   if (nullptr != sendingSegmentation && nullptr != removeEvent)
   {
     this->RemoveContours(sendingSegmentation, removeEvent->GetLabelValue());
   }
 }
 
 mitk::SurfaceInterpolationController::CPIVector* mitk::SurfaceInterpolationController::GetContours(LabelSetImage::LabelValueType labelValue, TimeStepType timeStep)
 {
   auto selectedSegmentation = m_SelectedSegmentation.Lock();
 
   if (selectedSegmentation == nullptr)
     return nullptr;
 
   std::shared_lock<std::shared_mutex> guard(cpiMutex);
 
   auto labelFinding = cpiMap[selectedSegmentation].find(labelValue);
 
   if (labelFinding != cpiMap[selectedSegmentation].end())
   {
     auto tsFinding = labelFinding->second.find(timeStep);
 
     if (tsFinding != labelFinding->second.end())
     {
       return &(tsFinding->second.cpis);
     }
   }
 
   return nullptr;
 }
 
 std::vector<mitk::LabelSetImage::LabelValueType> mitk::SurfaceInterpolationController::GetAffectedLabels(const LabelSetImage* seg, TimeStepType timeStep, const PlaneGeometry* plane) const
 {
   std::lock_guard<std::shared_mutex> guard(cpiMutex);
 
   std::vector<mitk::LabelSetImage::LabelValueType> result;
 
   auto finding = cpiMap.find(seg);
   if (finding == cpiMap.end()) return result;
   const auto& currentImageContours = cpiMap[seg];
 
   for (const auto& [label, contours] : currentImageContours)
   {
     auto tsFinding = contours.find(timeStep);
     if (tsFinding != contours.end())
     {
       const auto& cpis = contours.at(timeStep).cpis;
       auto finding = std::find_if(cpis.begin(), cpis.end(), [plane](const ContourPositionInformation& element) {return plane->IsOnPlane(element.Plane); });
 
       if (finding != cpis.end())
       {
         result.push_back(label);
       }
     }
   }
   return result;
 }
 
 
 void mitk::SurfaceInterpolationController::CompleteReinitialization(const std::vector<ContourPositionInformation>& newCPIs)
 {
   this->ClearInterpolationSession();
 
   //  Now the layers should be empty and the new layers can be added.
   this->AddNewContours(newCPIs, true);
 }
 
 void mitk::SurfaceInterpolationController::ClearInterpolationSession()
 {
   auto selectedSegmentation = m_SelectedSegmentation.Lock();
 
   if (selectedSegmentation != nullptr)
   {
     std::lock_guard<std::shared_mutex> guard(cpiMutex);
     cpiMap[selectedSegmentation].clear();
   }
 }