diff --git a/Modules/Segmentation/Interactions/mitkFillRegionBaseTool.cpp b/Modules/Segmentation/Interactions/mitkFillRegionBaseTool.cpp
index c539a758b6..c7326d1c79 100644
--- a/Modules/Segmentation/Interactions/mitkFillRegionBaseTool.cpp
+++ b/Modules/Segmentation/Interactions/mitkFillRegionBaseTool.cpp
@@ -1,147 +1,146 @@
 /*============================================================================
 
 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 "mitkFillRegionBaseTool.h"
 #include "mitkToolManager.h"
 
 #include "mitkBaseRenderer.h"
 #include "mitkDataStorage.h"
 
 #include "mitkITKImageImport.h"
 #include "mitkImageAccessByItk.h"
 
 #include "mitkRenderingManager.h"
 
 #include <itkConnectedThresholdImageFilter.h>
 
 mitk::FillRegionBaseTool::FillRegionBaseTool() : SegTool2D("MouseReleaseOnly")
 {
 }
 
 mitk::FillRegionBaseTool::~FillRegionBaseTool()
 {
 }
 
 void mitk::FillRegionBaseTool::ConnectActionsAndFunctions()
 {
   CONNECT_FUNCTION("Release", OnClick);
 }
 
 
 template <typename TPixel, unsigned int VImageDimension>
 void DoITKRegionGrowing(const itk::Image<TPixel, VImageDimension>* oldSegImage,
   mitk::Image::Pointer& filledRegionImage, itk::Index<VImageDimension> seedIndex, mitk::Label::PixelType& seedLabel )
 {
   typedef itk::Image<TPixel, VImageDimension> InputImageType;
   typedef itk::Image<mitk::Label::PixelType, VImageDimension> OutputImageType;
   typedef itk::ConnectedThresholdImageFilter<InputImageType, OutputImageType> RegionGrowingFilterType;
 
   seedLabel = oldSegImage->GetPixel(seedIndex);
 
   typename OutputImageType::Pointer itkResultImage;
   filledRegionImage = nullptr;
 
   try
   {
     typename RegionGrowingFilterType::Pointer regionGrower = RegionGrowingFilterType::New();
     regionGrower->SetInput(oldSegImage);
     regionGrower->SetReplaceValue(1);
     regionGrower->AddSeed(seedIndex);
 
     regionGrower->SetLower(seedLabel);
     regionGrower->SetUpper(seedLabel);
 
     regionGrower->Update();
     
     itkResultImage = regionGrower->GetOutput();
   }
   catch (const itk::ExceptionObject&)
   {
     return; // can't work
   }
   catch (...)
   {
     return;
   }
   mitk::CastToMitkImage(itkResultImage, filledRegionImage);
 }
 
 void mitk::FillRegionBaseTool::OnClick(StateMachineAction*, InteractionEvent* interactionEvent)
 {
   auto positionEvent = dynamic_cast<mitk::InteractionPositionEvent*>(interactionEvent);
   if (nullptr == positionEvent)
     return;
 
   auto labelSetImage = dynamic_cast<const LabelSetImage*>(this->GetWorkingData());
   if (nullptr == labelSetImage)
   {
     return;
   }
 
   if (!IsPositionEventInsideImageRegion(positionEvent, labelSetImage))
   {
     return;
   }
 
   m_LastEventSender = positionEvent->GetSender();
   m_LastEventSlice = m_LastEventSender->GetSlice();
 
   auto workingSlice = this->GetAffectedWorkingSlice(positionEvent);
 
   auto click = positionEvent->GetPositionInWorld();
 
   m_SeedLabelValue = 0;
   auto fillImage = this->GenerateFillImage(workingSlice, click, m_SeedLabelValue);
 
   if (fillImage.IsNull())
   {
     return; //nothing to fill;
   }
 
-  if (labelSetImage->IsLabelLocked(m_SeedLabelValue) && m_SeedLabelValue!=labelSetImage->GetActiveLabel(labelSetImage->GetActiveLayer())->GetValue())
+  if (labelSetImage->IsLabelLocked(m_SeedLabelValue) && m_SeedLabelValue!=labelSetImage->GetActiveLabel()->GetValue())
   {
     ErrorMessage.Send("Label of selected region is locked. Tool operation has no effect.");
     return;
   }
 
   this->PrepareFilling(workingSlice, click);
 
   //as fill region tools should always allow to manipulate active label
   //(that is what the user expects/knows when using tools so far:
   //the active label can always be changed even if locked)
   //we realize that by cloning the relevant label set and changing the lock state
   //this fillLabelSet is used for the transfer.
-  auto fillLabelSet = labelSetImage->GetActiveLabelSet()->Clone();
-  auto activeLabelClone = fillLabelSet->GetLabel(labelSetImage->GetActiveLabel(labelSetImage->GetActiveLayer())->GetValue());
+  auto activeLabelClone = labelSetImage->GetActiveLabel()->Clone();
   if (nullptr != activeLabelClone)
   {
     activeLabelClone->SetLocked(false);
   }
 
-  TransferLabelContentAtTimeStep(fillImage, workingSlice, fillLabelSet, 0, LabelSetImage::UnlabeledValue, LabelSetImage::UnlabeledValue, false, { {1, m_FillLabelValue} }, m_MergeStyle);
+  TransferLabelContentAtTimeStep(fillImage, workingSlice, { activeLabelClone }, 0, LabelSetImage::UnlabeledValue, LabelSetImage::UnlabeledValue, false, { {1, m_FillLabelValue} }, m_MergeStyle);
 
   this->WriteBackSegmentationResult(positionEvent, workingSlice);
 
   mitk::RenderingManager::GetInstance()->RequestUpdate(positionEvent->GetSender()->GetRenderWindow());
 }
 
 mitk::Image::Pointer mitk::FillRegionBaseTool::GenerateFillImage(const Image* workingSlice, Point3D seedPoint, mitk::Label::PixelType& seedLabelValue) const
 {
   itk::Index<2> seedIndex;
   workingSlice->GetGeometry()->WorldToIndex(seedPoint, seedIndex);
 
   Image::Pointer fillImage;
 
   AccessFixedDimensionByItk_n(workingSlice, DoITKRegionGrowing, 2, (fillImage, seedIndex, seedLabelValue));
 
   return fillImage;
 }
diff --git a/Modules/Segmentation/Interactions/mitkFillRegionTool.cpp b/Modules/Segmentation/Interactions/mitkFillRegionTool.cpp
index 296e8f613c..bde58bce1a 100644
--- a/Modules/Segmentation/Interactions/mitkFillRegionTool.cpp
+++ b/Modules/Segmentation/Interactions/mitkFillRegionTool.cpp
@@ -1,59 +1,59 @@
 /*============================================================================
 
 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 "mitkFillRegionTool.h"
 
 // us
 #include <usGetModuleContext.h>
 #include <usModule.h>
 #include <usModuleContext.h>
 #include <usModuleResource.h>
 
 namespace mitk
 {
   MITK_TOOL_MACRO(MITKSEGMENTATION_EXPORT, FillRegionTool, "Fill tool");
 }
 
 const char **mitk::FillRegionTool::GetXPM() const
 {
   return nullptr;
 }
 
 us::ModuleResource mitk::FillRegionTool::GetIconResource() const
 {
   us::Module *module = us::GetModuleContext()->GetModule();
   us::ModuleResource resource = module->GetResource("Fill.svg");
   return resource;
 }
 
 us::ModuleResource mitk::FillRegionTool::GetCursorIconResource() const
 {
   us::Module *module = us::GetModuleContext()->GetModule();
   us::ModuleResource resource = module->GetResource("Fill_Cursor.svg");
   return resource;
 }
 
 const char *mitk::FillRegionTool::GetName() const
 {
   return "Fill";
 }
 
 void mitk::FillRegionTool::PrepareFilling(const Image* /*workingSlice*/, Point3D /*seedPoint*/)
 {
   auto labelSetImage = dynamic_cast<const LabelSetImage*>(this->GetWorkingData());
 
   if (nullptr == labelSetImage) mitkThrow() << "Invalid state of FillRegionTool. Working image is not of correct type.";
 
-  m_FillLabelValue = labelSetImage->GetActiveLabel(labelSetImage->GetActiveLayer())->GetValue();
+  m_FillLabelValue = labelSetImage->GetActiveLabel()->GetValue();
   m_MergeStyle = MultiLabelSegmentation::MergeStyle::Merge;
 };
 
diff --git a/Modules/Segmentation/Interactions/mitkOtsuTool3D.cpp b/Modules/Segmentation/Interactions/mitkOtsuTool3D.cpp
index 688412dd2e..d07c107ce8 100644
--- a/Modules/Segmentation/Interactions/mitkOtsuTool3D.cpp
+++ b/Modules/Segmentation/Interactions/mitkOtsuTool3D.cpp
@@ -1,114 +1,110 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 // MITK
 #include "mitkOtsuTool3D.h"
 #include "mitkOtsuSegmentationFilter.h"
 #include <mitkLabelSetImageHelper.h>
 #include <mitkImageStatisticsHolder.h>
 
 // us
 #include <usGetModuleContext.h>
 #include <usModule.h>
 #include <usModuleContext.h>
 #include <usModuleResource.h>
 
 namespace mitk
 {
   MITK_TOOL_MACRO(MITKSEGMENTATION_EXPORT, OtsuTool3D, "Otsu Segmentation");
 }
 
 mitk::OtsuTool3D::OtsuTool3D()
   : SegWithPreviewTool()
 {
   this->ResetsToEmptyPreviewOn();
   this->UseSpecialPreviewColorOff();
 }
 
 void mitk::OtsuTool3D::Activated()
 {
   Superclass::Activated();
 
   m_NumberOfBins = 128;
   m_NumberOfRegions = 2;
   m_UseValley = false;
   this->SetLabelTransferScope(LabelTransferScope::AllLabels);
   this->SetLabelTransferMode(LabelTransferMode::AddLabel);
 }
 
 const char **mitk::OtsuTool3D::GetXPM() const
 {
   return nullptr;
 }
 
 us::ModuleResource mitk::OtsuTool3D::GetIconResource() const
 {
   us::Module *module = us::GetModuleContext()->GetModule();
   us::ModuleResource resource = module->GetResource("Otsu.svg");
   return resource;
 }
 
 const char* mitk::OtsuTool3D::GetName() const
 {
   return "Otsu";
 }
 
 void mitk::OtsuTool3D::DoUpdatePreview(const Image* inputAtTimeStep, const Image* /*oldSegAtTimeStep*/, LabelSetImage* previewImage, TimeStepType timeStep)
 {
   int numberOfThresholds = m_NumberOfRegions - 1;
 
   mitk::OtsuSegmentationFilter::Pointer otsuFilter = mitk::OtsuSegmentationFilter::New();
   otsuFilter->SetNumberOfThresholds(numberOfThresholds);
   otsuFilter->SetValleyEmphasis(m_UseValley);
   otsuFilter->SetNumberOfBins(m_NumberOfBins);
   otsuFilter->SetInput(inputAtTimeStep);
   otsuFilter->AddObserver(itk::ProgressEvent(), m_ProgressCommand);
 
   try
   {
     otsuFilter->Update();
   }
   catch (...)
   {
     mitkThrow() << "itkOtsuFilter error (image dimension must be in {2, 3} and image must not be RGB)";
   }
 
   auto otsuResultImage = otsuFilter->GetOutput();
 
   mitk::ImageReadAccessor newMitkImgAcc(otsuResultImage);
   previewImage->SetVolume(newMitkImgAcc.GetData(), timeStep);
 }
 
 void mitk::OtsuTool3D::UpdatePrepare()
 {
   Superclass::UpdatePrepare();
   auto preview = this->GetPreviewSegmentation();
-  auto labelset = preview->GetLabelSet(preview->GetActiveLayer());
-  for (LabelSetImage::GroupIndexType i = 0; i<preview->GetNumberOfLayers(); ++i)
-  {
-    preview->GetLabelSet(i)->RemoveAllLabels();
-  }
+  preview->RemoveLabels(preview->GetAllLabelValues());
 
   for (unsigned int i = 0; i < m_NumberOfRegions; ++i)
   {
-    auto label = LabelSetImageHelper::CreateNewLabel(preview, "Otsu");
+    auto label = LabelSetImageHelper::CreateNewLabel(preview, "Otsu " + std::to_string(i));
     label->SetValue(i + 1);
-    labelset->AddLabel(label, false);
+    preview->AddLabel(label, preview->GetActiveLayer(), false, false);
   }
 }
 
 unsigned int mitk::OtsuTool3D::GetMaxNumberOfBins() const
 {
   const auto min = this->GetReferenceData()->GetStatistics()->GetScalarValueMin();
   const auto max = this->GetReferenceData()->GetStatistics()->GetScalarValueMaxNoRecompute();
   return static_cast<unsigned int>(max - min) + 1;
 }
diff --git a/Modules/Segmentation/Interactions/mitkPaintbrushTool.cpp b/Modules/Segmentation/Interactions/mitkPaintbrushTool.cpp
index 288818e7d7..528be87fe1 100644
--- a/Modules/Segmentation/Interactions/mitkPaintbrushTool.cpp
+++ b/Modules/Segmentation/Interactions/mitkPaintbrushTool.cpp
@@ -1,612 +1,611 @@
 /*============================================================================
 
 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 "mitkPaintbrushTool.h"
 
 #include "mitkAbstractTransformGeometry.h"
 #include "mitkBaseRenderer.h"
 #include "mitkToolManager.h"
 
 #include "mitkContourModelUtils.h"
 #include "mitkLevelWindowProperty.h"
 #include "mitkImageWriteAccessor.h"
 
 int mitk::PaintbrushTool::m_Size = 1;
 
 mitk::PaintbrushTool::PaintbrushTool(bool startWithFillMode)
   : FeedbackContourTool("PressMoveReleaseWithCTRLInversionAllMouseMoves"),
   m_FillMode(startWithFillMode),
     m_LastContourSize(0) // other than initial mitk::PaintbrushTool::m_Size (around l. 28)
 {
   m_MasterContour = ContourModel::New();
   m_MasterContour->Initialize();
   m_CurrentPlane = nullptr;
 }
 
 mitk::PaintbrushTool::~PaintbrushTool()
 {
 }
 
 void mitk::PaintbrushTool::ConnectActionsAndFunctions()
 {
   CONNECT_FUNCTION("PrimaryButtonPressed", OnMousePressed);
   CONNECT_FUNCTION("Move", OnPrimaryButtonPressedMoved);
   CONNECT_FUNCTION("MouseMove", OnMouseMoved);
   CONNECT_FUNCTION("Release", OnMouseReleased);
   CONNECT_FUNCTION("InvertLogic", OnInvertLogic);
 }
 
 void mitk::PaintbrushTool::Activated()
 {
   Superclass::Activated();
 
   SizeChanged.Send(m_Size);
   this->GetToolManager()->WorkingDataChanged +=
     mitk::MessageDelegate<mitk::PaintbrushTool>(this, &mitk::PaintbrushTool::OnToolManagerWorkingDataModified);
 
   m_PaintingNode = DataNode::New();
   m_PaintingNode->SetProperty("levelwindow", mitk::LevelWindowProperty::New(mitk::LevelWindow(0, m_InternalFillValue)));
   m_PaintingNode->SetProperty("binary", mitk::BoolProperty::New(true));
 
   m_PaintingNode->SetProperty("outline binary", mitk::BoolProperty::New(true));
   m_PaintingNode->SetProperty("name", mitk::StringProperty::New("Paintbrush_Node"));
   m_PaintingNode->SetProperty("helper object", mitk::BoolProperty::New(true));
   m_PaintingNode->SetProperty("opacity", mitk::FloatProperty::New(0.8));
   m_PaintingNode->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false));
   auto allRenderWindows = BaseRenderer::GetAll3DRenderWindows();
   for (auto mapit = allRenderWindows.begin(); mapit != allRenderWindows.end(); ++mapit)
   {
     m_PaintingNode->SetVisibility(false, mapit->second);
   }
 
   this->UpdateFeedbackColor();
   FeedbackContourTool::SetFeedbackContourVisible(true);
 
   this->GetToolManager()->GetDataStorage()->Add(m_PaintingNode);
 }
 
 void mitk::PaintbrushTool::Deactivated()
 {
   FeedbackContourTool::SetFeedbackContourVisible(false);
   if (this->GetToolManager()->GetDataStorage()->Exists(m_PaintingNode))
     this->GetToolManager()->GetDataStorage()->Remove(m_PaintingNode);
   m_WorkingSlice = nullptr;
   m_PaintingSlice = nullptr;
   m_CurrentPlane = nullptr;
   m_PaintingNode = nullptr;
 
   this->GetToolManager()->WorkingDataChanged -=
     mitk::MessageDelegate<mitk::PaintbrushTool>(this, &mitk::PaintbrushTool::OnToolManagerWorkingDataModified);
 
   Superclass::Deactivated();
 }
 
 void mitk::PaintbrushTool::SetSize(int value)
 {
   m_Size = value;
 }
 
 mitk::Point2D mitk::PaintbrushTool::upperLeft(mitk::Point2D p)
 {
   p[0] -= 0.5;
   p[1] += 0.5;
   return p;
 }
 
 void mitk::PaintbrushTool::UpdateContour(const InteractionPositionEvent *positionEvent)
 {
   // MITK_INFO<<"Update...";
   // examine stateEvent and create a contour that matches the pixel mask that we are going to draw
   // mitk::InteractionPositionEvent* positionEvent = dynamic_cast<mitk::InteractionPositionEvent*>( interactionEvent );
   // const PositionEvent* positionEvent = dynamic_cast<const PositionEvent*>(stateEvent->GetEvent());
   if (!positionEvent)
     return;
 
   // Get Spacing of current Slice
   // mitk::Vector3D vSpacing = m_WorkingSlice->GetSlicedGeometry()->GetPlaneGeometry(0)->GetSpacing();
 
   //
   // Draw a contour in Square according to selected brush size
   //
   int radius = (m_Size) / 2;
   float fradius = static_cast<float>(m_Size) / 2.0f;
 
   ContourModel::Pointer contourInImageIndexCoordinates = ContourModel::New();
 
   // estimate center point of the brush ( relative to the pixel the mouse points on )
   // -- left upper corner for even sizes,
   // -- midpoint for uneven sizes
   mitk::Point2D centerCorrection;
   centerCorrection.Fill(0);
 
   // even --> correction of [+0.5, +0.5]
   bool evenSize = ((m_Size % 2) == 0);
   if (evenSize)
   {
     centerCorrection[0] += 0.5;
     centerCorrection[1] += 0.5;
   }
 
   // we will compute the control points for the upper left quarter part of a circle contour
   std::vector<mitk::Point2D> quarterCycleUpperRight;
   std::vector<mitk::Point2D> quarterCycleLowerRight;
   std::vector<mitk::Point2D> quarterCycleLowerLeft;
   std::vector<mitk::Point2D> quarterCycleUpperLeft;
 
   mitk::Point2D curPoint;
   bool curPointIsInside = true;
   curPoint[0] = 0;
   curPoint[1] = radius;
   quarterCycleUpperRight.push_back(upperLeft(curPoint));
 
   // to estimate if a pixel is inside the circle, we need to compare against the 'outer radius'
   // i.e. the distance from the midpoint [0,0] to the border of the pixel [0,radius]
   // const float outer_radius = static_cast<float>(radius) + 0.5;
 
   while (curPoint[1] > 0)
   {
     // Move right until pixel is outside circle
     float curPointX_squared = 0.0f;
     float curPointY_squared = (curPoint[1] - centerCorrection[1]) * (curPoint[1] - centerCorrection[1]);
     while (curPointIsInside)
     {
       // increment posX and chec
       curPoint[0]++;
       curPointX_squared = (curPoint[0] - centerCorrection[0]) * (curPoint[0] - centerCorrection[0]);
       const float len = sqrt(curPointX_squared + curPointY_squared);
       if (len > fradius)
       {
         // found first Pixel in this horizontal line, that is outside the circle
         curPointIsInside = false;
       }
     }
     quarterCycleUpperRight.push_back(upperLeft(curPoint));
 
     // Move down until pixel is inside circle
     while (!curPointIsInside)
     {
       // increment posX and chec
       curPoint[1]--;
       curPointY_squared = (curPoint[1] - centerCorrection[1]) * (curPoint[1] - centerCorrection[1]);
       const float len = sqrt(curPointX_squared + curPointY_squared);
       if (len <= fradius)
       {
         // found first Pixel in this horizontal line, that is outside the circle
         curPointIsInside = true;
         quarterCycleUpperRight.push_back(upperLeft(curPoint));
       }
 
       // Quarter cycle is full, when curPoint y position is 0
       if (curPoint[1] <= 0)
         break;
     }
   }
 
   // QuarterCycle is full! Now copy quarter cycle to other quarters.
 
   if (!evenSize)
   {
     std::vector<mitk::Point2D>::const_iterator it = quarterCycleUpperRight.begin();
     while (it != quarterCycleUpperRight.end())
     {
       mitk::Point2D p;
       p = *it;
 
       // the contour points in the lower right corner have same position but with negative y values
       p[1] *= -1;
       quarterCycleLowerRight.push_back(p);
 
       // the contour points in the lower left corner have same position
       // but with both x,y negative
       p[0] *= -1;
       quarterCycleLowerLeft.push_back(p);
 
       // the contour points in the upper left corner have same position
       // but with x negative
       p[1] *= -1;
       quarterCycleUpperLeft.push_back(p);
 
       it++;
     }
   }
   else
   {
     std::vector<mitk::Point2D>::const_iterator it = quarterCycleUpperRight.begin();
     while (it != quarterCycleUpperRight.end())
     {
       mitk::Point2D p, q;
       p = *it;
 
       q = p;
       // the contour points in the lower right corner have same position but with negative y values
       q[1] *= -1;
       // correct for moved offset if size even = the midpoint is not the midpoint of the current pixel
       // but its upper rigt corner
       q[1] += 1;
       quarterCycleLowerRight.push_back(q);
 
       q = p;
       // the contour points in the lower left corner have same position
       // but with both x,y negative
       q[1] = -1.0f * q[1] + 1;
       q[0] = -1.0f * q[0] + 1;
       quarterCycleLowerLeft.push_back(q);
 
       // the contour points in the upper left corner have same position
       // but with x negative
       q = p;
       q[0] *= -1;
       q[0] += 1;
       quarterCycleUpperLeft.push_back(q);
 
       it++;
     }
   }
 
   // fill contour with poins in right ordering, starting with the upperRight block
   mitk::Point3D tempPoint;
   for (unsigned int i = 0; i < quarterCycleUpperRight.size(); i++)
   {
     tempPoint[0] = quarterCycleUpperRight[i][0];
     tempPoint[1] = quarterCycleUpperRight[i][1];
     tempPoint[2] = 0;
     contourInImageIndexCoordinates->AddVertex(tempPoint);
   }
   // the lower right has to be parsed in reverse order
   for (int i = quarterCycleLowerRight.size() - 1; i >= 0; i--)
   {
     tempPoint[0] = quarterCycleLowerRight[i][0];
     tempPoint[1] = quarterCycleLowerRight[i][1];
     tempPoint[2] = 0;
     contourInImageIndexCoordinates->AddVertex(tempPoint);
   }
   for (unsigned int i = 0; i < quarterCycleLowerLeft.size(); i++)
   {
     tempPoint[0] = quarterCycleLowerLeft[i][0];
     tempPoint[1] = quarterCycleLowerLeft[i][1];
     tempPoint[2] = 0;
     contourInImageIndexCoordinates->AddVertex(tempPoint);
   }
   // the upper left also has to be parsed in reverse order
   for (int i = quarterCycleUpperLeft.size() - 1; i >= 0; i--)
   {
     tempPoint[0] = quarterCycleUpperLeft[i][0];
     tempPoint[1] = quarterCycleUpperLeft[i][1];
     tempPoint[2] = 0;
     contourInImageIndexCoordinates->AddVertex(tempPoint);
   }
 
   m_MasterContour = contourInImageIndexCoordinates;
 }
 
 void mitk::PaintbrushTool::OnMousePressed(StateMachineAction *, InteractionEvent *interactionEvent)
 {
   if (m_WorkingSlice.IsNull())
     return;
 
   auto* positionEvent = dynamic_cast<mitk::InteractionPositionEvent*>(interactionEvent);
   if (!positionEvent)
     return;
 
   this->ResetWorkingSlice(positionEvent);
 
   m_WorkingSlice->GetGeometry()->WorldToIndex(positionEvent->GetPositionInWorld(), m_LastPosition);
   this->m_PaintingNode->SetVisibility(true);
 
   m_LastEventSender = positionEvent->GetSender();
   m_LastEventSlice = m_LastEventSender->GetSlice();
   m_MasterContour->SetClosed(true);
   this->MouseMoved(interactionEvent, true);
 }
 
 void mitk::PaintbrushTool::OnMouseMoved(StateMachineAction *, InteractionEvent *interactionEvent)
 {
   MouseMoved(interactionEvent, false);
 }
 
 void mitk::PaintbrushTool::OnPrimaryButtonPressedMoved(StateMachineAction *, InteractionEvent *interactionEvent)
 {
   MouseMoved(interactionEvent, true);
 }
 
 /**
   Insert the point to the feedback contour,finish to build the contour and at the same time the painting function
   */
 void mitk::PaintbrushTool::MouseMoved(mitk::InteractionEvent *interactionEvent, bool leftMouseButtonPressed)
 {
   auto *positionEvent = dynamic_cast<mitk::InteractionPositionEvent *>(interactionEvent);
 
   bool newSlice = CheckIfCurrentSliceHasChanged(positionEvent);
   if (newSlice)
   {
     this->ResetWorkingSlice(positionEvent);
   }
 
   if (m_LastContourSize != m_Size)
   {
     UpdateContour(positionEvent);
     m_LastContourSize = m_Size;
   }
 
   Point3D worldCoordinates = positionEvent->GetPositionInWorld();
   Point3D indexCoordinates;
 
   m_WorkingSlice->GetGeometry()->WorldToIndex(worldCoordinates, indexCoordinates);
 
   // round to nearest voxel center (abort if this hasn't changed)
   if (m_Size % 2 == 0) // even
   {
     indexCoordinates[0] = std::round(indexCoordinates[0]);
     indexCoordinates[1] = std::round(indexCoordinates[1]);
   }
   else // odd
   {
     indexCoordinates[0] = std::round(indexCoordinates[0]);
     indexCoordinates[1] = std::round(indexCoordinates[1]);
   }
 
   static Point3D lastPos; // uninitialized: if somebody finds out how this can be initialized in a one-liner, tell me
   if (fabs(indexCoordinates[0] - lastPos[0]) > mitk::eps || fabs(indexCoordinates[1] - lastPos[1]) > mitk::eps ||
       fabs(indexCoordinates[2] - lastPos[2]) > mitk::eps || leftMouseButtonPressed)
   {
     lastPos = indexCoordinates;
   }
   else
   {
     return;
   }
 
   auto contour = ContourModel::New();
   contour->SetClosed(true);
 
   auto it = m_MasterContour->Begin();
   auto end = m_MasterContour->End();
 
   while (it != end)
   {
     auto point = (*it)->Coordinates;
     point[0] += indexCoordinates[0];
     point[1] += indexCoordinates[1];
 
     contour->AddVertex(point);
     ++it;
   }
 
   if (leftMouseButtonPressed)
   {
     ContourModelUtils::FillContourInSlice2(contour, m_PaintingSlice, m_InternalFillValue);
 
     const double dist = indexCoordinates.EuclideanDistanceTo(m_LastPosition);
     const double radius = static_cast<double>(m_Size) / 2.0;
 
     // if points are >= radius away draw rectangle to fill empty holes
     // in between the 2 points
     if (dist > radius)
     {
       const mitk::Point3D &currentPos = indexCoordinates;
       mitk::Point3D direction;
       mitk::Point3D vertex;
       mitk::Point3D normal;
 
       direction[0] = indexCoordinates[0] - m_LastPosition[0];
       direction[1] = indexCoordinates[1] - m_LastPosition[1];
       direction[2] = indexCoordinates[2] - m_LastPosition[2];
 
       direction[0] = direction.GetVnlVector().normalize()[0];
       direction[1] = direction.GetVnlVector().normalize()[1];
       direction[2] = direction.GetVnlVector().normalize()[2];
 
       // 90 degrees rotation of direction
       normal[0] = -1.0 * direction[1];
       normal[1] = direction[0];
 
       auto gapContour = ContourModel::New();
 
       // upper left corner
       vertex[0] = m_LastPosition[0] + (normal[0] * radius);
       vertex[1] = m_LastPosition[1] + (normal[1] * radius);
 
       gapContour->AddVertex(vertex);
 
       // upper right corner
       vertex[0] = currentPos[0] + (normal[0] * radius);
       vertex[1] = currentPos[1] + (normal[1] * radius);
 
       gapContour->AddVertex(vertex);
 
       // lower right corner
       vertex[0] = currentPos[0] - (normal[0] * radius);
       vertex[1] = currentPos[1] - (normal[1] * radius);
 
       gapContour->AddVertex(vertex);
 
       // lower left corner
       vertex[0] = m_LastPosition[0] - (normal[0] * radius);
       vertex[1] = m_LastPosition[1] - (normal[1] * radius);
 
       gapContour->AddVertex(vertex);
 
       ContourModelUtils::FillContourInSlice2(gapContour, m_PaintingSlice, m_InternalFillValue);
     }
   }
   else
   {
     // switched from different renderwindow
     // no activate hover highlighting. Otherwise undo / redo wont work
     this->m_PaintingNode->SetVisibility(false);
   }
 
   m_LastPosition = indexCoordinates;
 
   // visualize contour
   ContourModel::Pointer tmp =
     FeedbackContourTool::BackProjectContourFrom2DSlice(m_WorkingSlice->GetGeometry(), contour);
 
   this->UpdateCurrentFeedbackContour(tmp);
 
   if (newSlice)
   {
     RenderingManager::GetInstance()->RequestUpdateAll();
   }
   else
   {
     assert(positionEvent->GetSender()->GetRenderWindow());
     RenderingManager::GetInstance()->RequestUpdate(positionEvent->GetSender()->GetRenderWindow());
   }
 }
 
 void mitk::PaintbrushTool::OnMouseReleased(StateMachineAction *, InteractionEvent *interactionEvent)
 {
   // When mouse is released write segmentationresult back into image
   auto *positionEvent = dynamic_cast<mitk::InteractionPositionEvent *>(interactionEvent);
   if (!positionEvent)
     return;
 
   DataNode* workingNode(this->GetToolManager()->GetWorkingData(0));
   auto workingImage = dynamic_cast<LabelSetImage*>(workingNode->GetData());
   Label::PixelType activePixelValue = ContourModelUtils::GetActivePixelValue(workingImage);
   if (!m_FillMode)
   {
     activePixelValue = LabelSetImage::UnlabeledValue;
   }
 
   //as paintbrush tools should always allow to manipulate active label
   //(that is what the user expects/knows when using tools so far:
   //the active label can always be changed even if locked)
   //we realize that by cloning the relevant label set and changing the lock state
   //this fillLabelSet is used for the transfer.
-  auto fillLabelSet = workingImage->GetActiveLabelSet()->Clone();
-  auto activeLabelClone = fillLabelSet->GetLabel(workingImage->GetActiveLabel(workingImage->GetActiveLayer())->GetValue());
+  auto activeLabelClone = workingImage->GetActiveLabel()->Clone();
   if (nullptr != activeLabelClone)
   {
     activeLabelClone->SetLocked(false);
   }
 
-  TransferLabelContentAtTimeStep(m_PaintingSlice, m_WorkingSlice, fillLabelSet, 0, LabelSetImage::UnlabeledValue, LabelSetImage::UnlabeledValue, false, { {m_InternalFillValue, activePixelValue} }, mitk::MultiLabelSegmentation::MergeStyle::Merge);
+  TransferLabelContentAtTimeStep(m_PaintingSlice, m_WorkingSlice, { activeLabelClone }, 0, LabelSetImage::UnlabeledValue, LabelSetImage::UnlabeledValue, false, { {m_InternalFillValue, activePixelValue} }, mitk::MultiLabelSegmentation::MergeStyle::Merge);
 
   this->WriteBackSegmentationResult(positionEvent, m_WorkingSlice->Clone());
 
   // deactivate visibility of helper node
   m_PaintingNode->SetVisibility(false);
   m_PaintingNode->SetData(nullptr);
   m_PaintingSlice = nullptr;
   m_WorkingSlice = nullptr;
 
   RenderingManager::GetInstance()->RequestUpdateAll();
 }
 
 void mitk::PaintbrushTool::UpdateFeedbackColor()
 {
   mitk::Color currentColor;
   if (m_FillMode)
   {
     FeedbackContourTool::SetFeedbackContourColorDefault();
     currentColor.Set(0.0, 1.0, 0.);
   }
   else
   {
     FeedbackContourTool::SetFeedbackContourColor(1.0, 0.0, 0.0);
     currentColor.Set(1.0, 0.0, 0.);
   }
 
   if (m_PaintingNode.IsNotNull())
   {
     m_PaintingNode->SetProperty("color", mitk::ColorProperty::New(currentColor[0], currentColor[1], currentColor[2]));
   }
 }
 
 /**
   Called when the CTRL key is pressed.
   */
 void mitk::PaintbrushTool::OnInvertLogic(StateMachineAction *, InteractionEvent *)
 {
   m_FillMode = !m_FillMode;
   UpdateFeedbackColor();
 
   mitk::RenderingManager::GetInstance()->RequestUpdateAll();
 }
 
 bool mitk::PaintbrushTool::CheckIfCurrentSliceHasChanged(const InteractionPositionEvent *event)
 {
   const PlaneGeometry* planeGeometry((event->GetSender()->GetCurrentWorldPlaneGeometry()));
   const auto* abstractTransformGeometry(
     dynamic_cast<const AbstractTransformGeometry *>(event->GetSender()->GetCurrentWorldPlaneGeometry()));
   if (nullptr == planeGeometry || nullptr != abstractTransformGeometry)
   {
     return false;
   }
 
   bool newPlane = false;
 
   if (m_CurrentPlane.IsNull() || m_WorkingSlice.IsNull()
       //or not the same slice
      || !mitk::MatrixEqualElementWise(planeGeometry->GetIndexToWorldTransform()->GetMatrix(),
        m_CurrentPlane->GetIndexToWorldTransform()->GetMatrix())
      || !mitk::Equal(planeGeometry->GetIndexToWorldTransform()->GetOffset(),
        m_CurrentPlane->GetIndexToWorldTransform()->GetOffset()))
   {
     m_CurrentPlane = planeGeometry;
     newPlane = true;
   }
 
   return newPlane;
 }
 
 void mitk::PaintbrushTool::ResetWorkingSlice(const InteractionPositionEvent* event)
 {
   const PlaneGeometry* planeGeometry((event->GetSender()->GetCurrentWorldPlaneGeometry()));
   const auto* abstractTransformGeometry(
     dynamic_cast<const AbstractTransformGeometry*>(event->GetSender()->GetCurrentWorldPlaneGeometry()));
   if (nullptr == planeGeometry || nullptr != abstractTransformGeometry)
   {
     return;
   }
 
   m_WorkingSlice = nullptr;
   m_PaintingSlice = nullptr;
   m_PaintingNode->SetData(nullptr);
 
   DataNode* workingNode = this->GetToolManager()->GetWorkingData(0);
   if (nullptr == workingNode)
   {
     return;
   }
 
   Image::Pointer image = dynamic_cast<Image*>(workingNode->GetData());
   if (nullptr == image)
   {
     return;
   }
 
   m_WorkingSlice = SegTool2D::GetAffectedImageSliceAs2DImage(event, image)->Clone();
 
   m_PaintingSlice = Image::New();
   m_PaintingSlice->Initialize(m_WorkingSlice);
 
   unsigned int byteSize = m_PaintingSlice->GetPixelType().GetSize();
   for (unsigned int dim = 0; dim < m_PaintingSlice->GetDimension(); ++dim)
   {
     byteSize *= m_PaintingSlice->GetDimension(dim);
   }
   mitk::ImageWriteAccessor writeAccess(m_PaintingSlice.GetPointer(), m_PaintingSlice->GetVolumeData(0));
   memset(writeAccess.GetData(), 0, byteSize);
 
   m_PaintingNode->SetData(m_PaintingSlice);
 }
 
 void mitk::PaintbrushTool::OnToolManagerWorkingDataModified()
 {
   // Here we simply set the current working slice to null. The next time the mouse is moved
   // within a renderwindow a new slice will be extracted from the new working data
   m_WorkingSlice = nullptr;
   m_PaintingSlice = nullptr;
 }
diff --git a/Modules/Segmentation/Interactions/mitkSegTool2D.cpp b/Modules/Segmentation/Interactions/mitkSegTool2D.cpp
index 3cab141cdc..f5ef7c5df5 100644
--- a/Modules/Segmentation/Interactions/mitkSegTool2D.cpp
+++ b/Modules/Segmentation/Interactions/mitkSegTool2D.cpp
@@ -1,798 +1,798 @@
 /*============================================================================
 
 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 "mitkSegTool2D.h"
 #include "mitkToolManager.h"
 
 #include "mitkBaseRenderer.h"
 #include "mitkDataStorage.h"
 #include "mitkPlaneGeometry.h"
 #include <mitkTimeNavigationController.h>
 
 // Include of the new ImageExtractor
 #include "mitkMorphologicalOperations.h"
 #include "mitkPlanarCircle.h"
 
 #include "usGetModuleContext.h"
 
 // Includes for 3DSurfaceInterpolation
 #include "mitkImageTimeSelector.h"
 #include "mitkImageToContourFilter.h"
 #include "mitkSurfaceInterpolationController.h"
 
 // includes for resling and overwriting
 #include <mitkExtractSliceFilter.h>
 #include <mitkVtkImageOverwrite.h>
 #include <vtkImageData.h>
 #include <vtkSmartPointer.h>
 
 #include "mitkOperationEvent.h"
 #include "mitkUndoController.h"
 #include <mitkDiffSliceOperationApplier.h>
 
 #include "mitkAbstractTransformGeometry.h"
 #include "mitkLabelSetImage.h"
 
 #include "mitkContourModelUtils.h"
 
 // #include <itkImageRegionIterator.h>
 
 #include <vtkAbstractArray.h>
 #include <vtkFieldData.h>
 
 #define ROUND(a) ((a) > 0 ? (int)((a) + 0.5) : -(int)(0.5 - (a)))
 
 bool mitk::SegTool2D::m_SurfaceInterpolationEnabled = true;
 
 mitk::SegTool2D::SliceInformation::SliceInformation(const mitk::Image* aSlice, const mitk::PlaneGeometry* aPlane, mitk::TimeStepType aTimestep) :
   slice(aSlice), plane(aPlane), timestep(aTimestep)
 {
 }
 
 mitk::SegTool2D::SegTool2D(const char *type, const us::Module *interactorModule)
   : Tool(type, interactorModule), m_Contourmarkername("Position")
 {
   Tool::m_EventConfig = "DisplayConfigBlockLMB.xml";
 }
 
 mitk::SegTool2D::~SegTool2D()
 {
 }
 
 bool mitk::SegTool2D::FilterEvents(InteractionEvent *interactionEvent, DataNode *)
 {
   const auto *positionEvent = dynamic_cast<const InteractionPositionEvent *>(interactionEvent);
 
   bool isValidEvent =
     (positionEvent && // Only events of type mitk::InteractionPositionEvent
      interactionEvent->GetSender()->GetMapperID() == BaseRenderer::Standard2D // Only events from the 2D renderwindows
      );
   return isValidEvent;
 }
 
 bool mitk::SegTool2D::DetermineAffectedImageSlice(const Image *image,
                                                   const PlaneGeometry *plane,
                                                   int &affectedDimension,
                                                   int &affectedSlice)
 {
   assert(image);
   assert(plane);
 
   // compare normal of plane to the three axis vectors of the image
   Vector3D normal = plane->GetNormal();
   Vector3D imageNormal0 = image->GetSlicedGeometry()->GetAxisVector(0);
   Vector3D imageNormal1 = image->GetSlicedGeometry()->GetAxisVector(1);
   Vector3D imageNormal2 = image->GetSlicedGeometry()->GetAxisVector(2);
 
   normal.Normalize();
   imageNormal0.Normalize();
   imageNormal1.Normalize();
   imageNormal2.Normalize();
 
   imageNormal0.SetVnlVector(vnl_cross_3d<ScalarType>(normal.GetVnlVector(), imageNormal0.GetVnlVector()));
   imageNormal1.SetVnlVector(vnl_cross_3d<ScalarType>(normal.GetVnlVector(), imageNormal1.GetVnlVector()));
   imageNormal2.SetVnlVector(vnl_cross_3d<ScalarType>(normal.GetVnlVector(), imageNormal2.GetVnlVector()));
 
   double eps(0.00001);
   // axial
   if (imageNormal2.GetNorm() <= eps)
   {
     affectedDimension = 2;
   }
   // sagittal
   else if (imageNormal1.GetNorm() <= eps)
   {
     affectedDimension = 1;
   }
   // coronal
   else if (imageNormal0.GetNorm() <= eps)
   {
     affectedDimension = 0;
   }
   else
   {
     affectedDimension = -1; // no idea
     return false;
   }
 
   // determine slice number in image
   BaseGeometry *imageGeometry = image->GetGeometry(0);
   Point3D testPoint = imageGeometry->GetCenter();
   Point3D projectedPoint;
   plane->Project(testPoint, projectedPoint);
 
   Point3D indexPoint;
 
   imageGeometry->WorldToIndex(projectedPoint, indexPoint);
   affectedSlice = ROUND(indexPoint[affectedDimension]);
   MITK_DEBUG << "indexPoint " << indexPoint << " affectedDimension " << affectedDimension << " affectedSlice "
              << affectedSlice;
 
   // check if this index is still within the image
   if (affectedSlice < 0 || affectedSlice >= static_cast<int>(image->GetDimension(affectedDimension)))
     return false;
 
   return true;
 }
 
 void mitk::SegTool2D::UpdateSurfaceInterpolation(const Image *slice,
                                                  const Image *workingImage,
                                                  const PlaneGeometry *plane,
                                                  bool detectIntersection)
 {
   std::vector<SliceInformation> slices = { SliceInformation(slice, plane, 0)};
   Self::UpdateSurfaceInterpolation(slices, workingImage, detectIntersection, 0, 0);
 }
 
 void  mitk::SegTool2D::RemoveContourFromInterpolator(const SliceInformation& sliceInfo)
 {
   mitk::SurfaceInterpolationController::ContourPositionInformation contourInfo;
   contourInfo.ContourNormal = sliceInfo.plane->GetNormal();
   contourInfo.ContourPoint = sliceInfo.plane->GetOrigin();
   mitk::SurfaceInterpolationController::GetInstance()->RemoveContour(contourInfo);
 }
 
 void mitk::SegTool2D::UpdateSurfaceInterpolation(const std::vector<SliceInformation>& sliceInfos,
   const Image* workingImage,
   bool detectIntersection,
   unsigned int activeLayerID,
   mitk::Label::PixelType activeLabelValue)
 {
   if (!m_SurfaceInterpolationEnabled)
     return;
 
   //Remark: the ImageTimeSelector is just needed to extract a timestep/channel of
   //the image in order to get the image dimension (time dimension and channel dimension
   //stripped away). Therfore it is OK to always use time step 0 and channel 0
   mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New();
   timeSelector->SetInput(workingImage);
   timeSelector->SetTimeNr(0);
   timeSelector->SetChannelNr(0);
   timeSelector->Update();
   const auto dimRefImg = timeSelector->GetOutput()->GetDimension();
 
   if (dimRefImg != 3)
     return;
 
   std::vector<mitk::Surface::Pointer> contourList;
   contourList.reserve(sliceInfos.size());
 
   ImageToContourFilter::Pointer contourExtractor = ImageToContourFilter::New();
 
   std::vector<SliceInformation> relevantSlices = sliceInfos;
 
   if (detectIntersection)
   {
     relevantSlices.clear();
 
     for (const auto& sliceInfo : sliceInfos)
     {
       // Test whether there is something to extract or whether the slice just contains intersections of others
       mitk::Image::Pointer slice2 = sliceInfo.slice->Clone();
       mitk::MorphologicalOperations::Erode(slice2, 2, mitk::MorphologicalOperations::Ball);
 
       contourExtractor->SetInput(slice2);
       contourExtractor->Update();
       mitk::Surface::Pointer contour = contourExtractor->GetOutput();
 
       if (contour->GetVtkPolyData()->GetNumberOfPoints() == 0)
       {
         Self::RemoveContourFromInterpolator(sliceInfo);
       }
       else
       {
         relevantSlices.push_back(sliceInfo);
       }
     }
   }
 
   if (relevantSlices.empty())
     return;
 
   std::vector<const mitk::PlaneGeometry*> contourPlanes;
   for (const auto& sliceInfo : relevantSlices)
   {
     contourExtractor->SetInput(sliceInfo.slice);
     contourExtractor->SetContourValue(activeLabelValue);
     contourExtractor->Update();
     mitk::Surface::Pointer contour = contourExtractor->GetOutput();
 
     if (contour->GetVtkPolyData()->GetNumberOfPoints() == 0)
     {
       Self::RemoveContourFromInterpolator(sliceInfo);
     }
     else
     {
       vtkSmartPointer<vtkIntArray> intArray = vtkSmartPointer<vtkIntArray>::New();
       intArray->InsertNextValue(activeLabelValue);
       intArray->InsertNextValue(activeLayerID);
       contour->GetVtkPolyData()->GetFieldData()->AddArray(intArray);
       contour->DisconnectPipeline();
       contourList.push_back(contour);
       contourPlanes.push_back(sliceInfo.plane);
     }
   }
 
   mitk::SurfaceInterpolationController::GetInstance()->AddNewContours(contourList, contourPlanes);
 }
 
 
 
 mitk::Image::Pointer mitk::SegTool2D::GetAffectedImageSliceAs2DImage(const InteractionPositionEvent *positionEvent, const Image *image, unsigned int component /*= 0*/)
 {
   if (!positionEvent)
   {
     return nullptr;
   }
 
   assert(positionEvent->GetSender()); // sure, right?
   const auto timeStep = positionEvent->GetSender()->GetTimeStep(image); // get the timestep of the visible part (time-wise) of the image
 
   return GetAffectedImageSliceAs2DImage(positionEvent->GetSender()->GetCurrentWorldPlaneGeometry(), image, timeStep, component);
 }
 
 mitk::Image::Pointer mitk::SegTool2D::GetAffectedImageSliceAs2DImageByTimePoint(const PlaneGeometry* planeGeometry, const Image* image, TimePointType timePoint, unsigned int component /*= 0*/)
 {
   if (!image || !planeGeometry)
   {
     return nullptr;
   }
 
   if (!image->GetTimeGeometry()->IsValidTimePoint(timePoint))
     return nullptr;
 
   return SegTool2D::GetAffectedImageSliceAs2DImage(planeGeometry, image, image->GetTimeGeometry()->TimePointToTimeStep(timePoint), component);
 }
 
 
 mitk::Image::Pointer mitk::SegTool2D::GetAffectedImageSliceAs2DImage(const PlaneGeometry *planeGeometry, const Image *image, TimeStepType timeStep, unsigned int component /*= 0*/)
 {
   if (!image || !planeGeometry)
   {
     return nullptr;
   }
 
   // Make sure that for reslicing and overwriting the same alogrithm is used. We can specify the mode of the vtk reslicer
   vtkSmartPointer<mitkVtkImageOverwrite> reslice = vtkSmartPointer<mitkVtkImageOverwrite>::New();
   // set to false to extract a slice
   reslice->SetOverwriteMode(false);
   reslice->Modified();
 
   // use ExtractSliceFilter with our specific vtkImageReslice for overwriting and extracting
   mitk::ExtractSliceFilter::Pointer extractor = mitk::ExtractSliceFilter::New(reslice);
   extractor->SetInput(image);
   extractor->SetTimeStep(timeStep);
   extractor->SetWorldGeometry(planeGeometry);
   extractor->SetVtkOutputRequest(false);
   extractor->SetResliceTransformByGeometry(image->GetTimeGeometry()->GetGeometryForTimeStep(timeStep));
   // additionally extract the given component
   // default is 0; the extractor checks for multi-component images
   extractor->SetComponent(component);
 
   extractor->Modified();
   extractor->Update();
 
   Image::Pointer slice = extractor->GetOutput();
 
   return slice;
 }
 
 mitk::Image::Pointer mitk::SegTool2D::GetAffectedWorkingSlice(const InteractionPositionEvent *positionEvent) const
 {
   const auto workingNode = this->GetWorkingDataNode();
   if (!workingNode)
   {
     return nullptr;
   }
 
   const auto *workingImage = dynamic_cast<Image *>(workingNode->GetData());
   if (!workingImage)
   {
     return nullptr;
   }
 
   return GetAffectedImageSliceAs2DImage(positionEvent, workingImage);
 }
 
 mitk::Image::Pointer mitk::SegTool2D::GetAffectedReferenceSlice(const InteractionPositionEvent *positionEvent) const
 {
   DataNode* referenceNode = this->GetReferenceDataNode();
   if (!referenceNode)
   {
     return nullptr;
   }
 
   auto *referenceImage = dynamic_cast<Image *>(referenceNode->GetData());
   if (!referenceImage)
   {
     return nullptr;
   }
 
   int displayedComponent = 0;
   if (referenceNode->GetIntProperty("Image.Displayed Component", displayedComponent))
   {
     // found the displayed component
     return GetAffectedImageSliceAs2DImage(positionEvent, referenceImage, displayedComponent);
   }
   else
   {
     return GetAffectedImageSliceAs2DImage(positionEvent, referenceImage);
   }
 }
 
 mitk::Image::Pointer mitk::SegTool2D::GetAffectedReferenceSlice(const PlaneGeometry* planeGeometry, TimeStepType timeStep) const
 {
   DataNode* referenceNode = this->GetReferenceDataNode();
   if (!referenceNode)
   {
     return nullptr;
   }
 
   auto* referenceImage = dynamic_cast<Image*>(referenceNode->GetData());
   if (!referenceImage)
   {
     return nullptr;
   }
 
   int displayedComponent = 0;
   if (referenceNode->GetIntProperty("Image.Displayed Component", displayedComponent))
   {
     // found the displayed component
     return GetAffectedImageSliceAs2DImage(planeGeometry, referenceImage, timeStep, displayedComponent);
   }
   else
   {
     return GetAffectedImageSliceAs2DImage(planeGeometry, referenceImage, timeStep);
   }
 }
 
 void mitk::SegTool2D::Activated()
 {
   Superclass::Activated();
 
   this->GetToolManager()->SelectedTimePointChanged +=
     mitk::MessageDelegate<mitk::SegTool2D>(this, &mitk::SegTool2D::OnTimePointChangedInternal);
 
   m_LastTimePointTriggered = mitk::RenderingManager::GetInstance()->GetTimeNavigationController()->GetSelectedTimePoint();
 }
 
 void mitk::SegTool2D::Deactivated()
 {
   this->GetToolManager()->SelectedTimePointChanged -=
     mitk::MessageDelegate<mitk::SegTool2D>(this, &mitk::SegTool2D::OnTimePointChangedInternal);
   Superclass::Deactivated();
 }
 
 void mitk::SegTool2D::OnTimePointChangedInternal()
 {
   if (m_IsTimePointChangeAware && nullptr != this->GetWorkingDataNode())
   {
     const TimePointType timePoint = mitk::RenderingManager::GetInstance()->GetTimeNavigationController()->GetSelectedTimePoint();
     if (timePoint != m_LastTimePointTriggered)
     {
       m_LastTimePointTriggered = timePoint;
       this->OnTimePointChanged();
     }
   }
 }
 
 void mitk::SegTool2D::OnTimePointChanged()
 {
   //default implementation does nothing
 }
 
 mitk::DataNode* mitk::SegTool2D::GetWorkingDataNode() const
 {
   if (nullptr != this->GetToolManager())
   {
     return this->GetToolManager()->GetWorkingData(0);
   }
   return nullptr;
 }
 
 mitk::Image* mitk::SegTool2D::GetWorkingData() const
 {
   auto node = this->GetWorkingDataNode();
   if (nullptr != node)
   {
     return dynamic_cast<Image*>(node->GetData());
   }
   return nullptr;
 }
 
 mitk::DataNode* mitk::SegTool2D::GetReferenceDataNode() const
 {
   if (nullptr != this->GetToolManager())
   {
     return this->GetToolManager()->GetReferenceData(0);
   }
   return nullptr;
 }
 
 mitk::Image* mitk::SegTool2D::GetReferenceData() const
 {
   auto node = this->GetReferenceDataNode();
   if (nullptr != node)
   {
     return dynamic_cast<Image*>(node->GetData());
   }
   return nullptr;
 }
 
 
 void mitk::SegTool2D::WriteBackSegmentationResult(const InteractionPositionEvent *positionEvent, const Image * segmentationResult)
 {
   if (!positionEvent)
     return;
 
   const PlaneGeometry *planeGeometry((positionEvent->GetSender()->GetCurrentWorldPlaneGeometry()));
   const auto *abstractTransformGeometry(
     dynamic_cast<const AbstractTransformGeometry *>(positionEvent->GetSender()->GetCurrentWorldPlaneGeometry()));
 
   if (planeGeometry && segmentationResult && !abstractTransformGeometry)
   {
     const auto workingNode = this->GetWorkingDataNode();
     auto *image = dynamic_cast<Image *>(workingNode->GetData());
     const auto timeStep = positionEvent->GetSender()->GetTimeStep(image);
     this->WriteBackSegmentationResult(planeGeometry, segmentationResult, timeStep);
   }
 }
 
 void mitk::SegTool2D::WriteBackSegmentationResult(const DataNode* workingNode, const PlaneGeometry* planeGeometry, const Image* segmentationResult, TimeStepType timeStep)
 {
   if (!planeGeometry || !segmentationResult)
     return;
 
   SliceInformation sliceInfo(segmentationResult, const_cast<mitk::PlaneGeometry*>(planeGeometry), timeStep);
   Self::WriteBackSegmentationResults(workingNode, { sliceInfo }, true);
 }
 
 void mitk::SegTool2D::WriteBackSegmentationResult(const PlaneGeometry *planeGeometry,
                                                   const Image * segmentationResult,
                                                   TimeStepType timeStep)
 {
   if (!planeGeometry || !segmentationResult)
     return;
 
   if(m_LastEventSender == nullptr)
   {
     return;
   }
   unsigned int currentSlicePosition = m_LastEventSender->GetSliceNavigationController()->GetStepper()->GetPos();
   SliceInformation sliceInfo(segmentationResult, const_cast<mitk::PlaneGeometry *>(planeGeometry), timeStep);
   sliceInfo.slicePosition = currentSlicePosition;
   WriteBackSegmentationResults({ sliceInfo }, true);
 }
 
 void mitk::SegTool2D::WriteBackSegmentationResults(const std::vector<SegTool2D::SliceInformation> &sliceList,
                                                   bool writeSliceToVolume)
 {
   if (sliceList.empty())
   {
     return;
   }
 
   if (nullptr == m_LastEventSender)
   {
     MITK_WARN << "Cannot write tool results. Tool seems to be in an invalid state, as no interaction event was recieved but is expected.";
     return;
   }
 
   const auto workingNode = this->GetWorkingDataNode();
 
   // the first geometry is needed otherwise restoring the position is not working
   const auto* plane3 =
     dynamic_cast<const PlaneGeometry*>(dynamic_cast<const mitk::SlicedGeometry3D*>(
       m_LastEventSender->GetSliceNavigationController()->GetCurrentGeometry3D())
       ->GetPlaneGeometry(0));
   const unsigned int slicePosition = m_LastEventSender->GetSliceNavigationController()->GetStepper()->GetPos();
 
   mitk::SegTool2D::WriteBackSegmentationResults(workingNode, sliceList, writeSliceToVolume);
 
 
   /* A cleaner solution would be to add a contour marker for each slice info. It currently
    does not work as the contour markers expect that the plane is always the plane of slice 0.
    Had not the time to do it properly no. Should be solved by T28146*/
   this->AddContourmarker(plane3, slicePosition);
 }
 
 void mitk::SegTool2D::WriteBackSegmentationResults(const DataNode* workingNode, const std::vector<SliceInformation>& sliceList, bool writeSliceToVolume)
 {
   if (sliceList.empty())
   {
     return;
   }
 
   if (nullptr == workingNode)
   {
     mitkThrow() << "Cannot write slice to working node. Working node is invalid.";
   }
 
   auto image = dynamic_cast<Image*>(workingNode->GetData());
 
   mitk::Label::PixelType activeLabelValue = 0;
   unsigned int activeLayerID = 0;
 
   try{
     auto labelSetImage = dynamic_cast<mitk::LabelSetImage*>(workingNode->GetData());
     activeLayerID = labelSetImage->GetActiveLayer();
-    activeLabelValue = labelSetImage->GetActiveLabelSet()->GetActiveLabel()->GetValue();
+    activeLabelValue = labelSetImage->GetActiveLabel()->GetValue();
   }
   catch(...)
   {
     mitkThrow() << "Working node does not contain  labelSetImage.";
   }
 
 
   if (nullptr == image)
   {
     mitkThrow() << "Cannot write slice to working node. Working node does not contain an image.";
   }
 
   for (const auto& sliceInfo : sliceList)
   {
     if (writeSliceToVolume && nullptr != sliceInfo.plane && sliceInfo.slice.IsNotNull())
     {
       SegTool2D::WriteSliceToVolume(image, sliceInfo, true);
     }
   }
 
   SegTool2D::UpdateSurfaceInterpolation(sliceList, image, false, activeLayerID, activeLabelValue);
 
   // also mark its node as modified (T27308). Can be removed if T27307
   // is properly solved
   if (workingNode != nullptr) workingNode->Modified();
 
   mitk::RenderingManager::GetInstance()->RequestUpdateAll();
 }
 
 void mitk::SegTool2D::WriteSliceToVolume(Image* workingImage, const PlaneGeometry* planeGeometry, const Image* slice, TimeStepType timeStep, bool allowUndo)
 {
   SliceInformation sliceInfo(slice, planeGeometry, timeStep);
 
   WriteSliceToVolume(workingImage, sliceInfo, allowUndo);
 }
 
 void mitk::SegTool2D::WriteSliceToVolume(Image* workingImage, const SliceInformation &sliceInfo, bool allowUndo)
 {
   if (nullptr == workingImage)
   {
     mitkThrow() << "Cannot write slice to working node. Working node does not contain an image.";
   }
 
   DiffSliceOperation* undoOperation = nullptr;
 
   if (allowUndo)
   {
     /*============= BEGIN undo/redo feature block ========================*/
     // Create undo operation by caching the not yet modified slices
     mitk::Image::Pointer originalSlice = GetAffectedImageSliceAs2DImage(sliceInfo.plane, workingImage, sliceInfo.timestep);
     undoOperation =
       new DiffSliceOperation(workingImage,
         originalSlice,
         dynamic_cast<SlicedGeometry3D*>(originalSlice->GetGeometry()),
         sliceInfo.timestep,
         sliceInfo.plane);
     /*============= END undo/redo feature block ========================*/
   }
 
   // Make sure that for reslicing and overwriting the same alogrithm is used. We can specify the mode of the vtk
   // reslicer
   vtkSmartPointer<mitkVtkImageOverwrite> reslice = vtkSmartPointer<mitkVtkImageOverwrite>::New();
 
   // Set the slice as 'input'
   // casting const away is needed and OK as long the OverwriteMode of
   // mitkVTKImageOverwrite is true.
   // Reason: because then the input slice is not touched but
   // used to overwrite the input of the ExtractSliceFilter.
   auto noneConstSlice = const_cast<Image*>(sliceInfo.slice.GetPointer());
   reslice->SetInputSlice(noneConstSlice->GetVtkImageData());
 
   // set overwrite mode to true to write back to the image volume
   reslice->SetOverwriteMode(true);
   reslice->Modified();
 
   mitk::ExtractSliceFilter::Pointer extractor = mitk::ExtractSliceFilter::New(reslice);
   extractor->SetInput(workingImage);
   extractor->SetTimeStep(sliceInfo.timestep);
   extractor->SetWorldGeometry(sliceInfo.plane);
   extractor->SetVtkOutputRequest(false);
   extractor->SetResliceTransformByGeometry(workingImage->GetGeometry(sliceInfo.timestep));
 
   extractor->Modified();
   extractor->Update();
 
   // the image was modified within the pipeline, but not marked so
   workingImage->Modified();
   workingImage->GetVtkImageData()->Modified();
 
   if (allowUndo)
   {
     /*============= BEGIN undo/redo feature block ========================*/
     // specify the redo operation with the edited slice
     auto* doOperation =
       new DiffSliceOperation(workingImage,
         extractor->GetOutput(),
         dynamic_cast<SlicedGeometry3D*>(sliceInfo.slice->GetGeometry()),
         sliceInfo.timestep,
         sliceInfo.plane);
 
     // create an operation event for the undo stack
     OperationEvent* undoStackItem =
       new OperationEvent(DiffSliceOperationApplier::GetInstance(), doOperation, undoOperation, "Segmentation");
 
     // add it to the undo controller
     UndoStackItem::IncCurrObjectEventId();
     UndoStackItem::IncCurrGroupEventId();
     UndoController::GetCurrentUndoModel()->SetOperationEvent(undoStackItem);
     /*============= END undo/redo feature block ========================*/
   }
 }
 
 
 void mitk::SegTool2D::SetShowMarkerNodes(bool status)
 {
   m_ShowMarkerNodes = status;
 }
 
 void mitk::SegTool2D::SetEnable3DInterpolation(bool enabled)
 {
   m_SurfaceInterpolationEnabled = enabled;
 }
 
 int mitk::SegTool2D::AddContourmarker(const PlaneGeometry* planeGeometry, unsigned int sliceIndex)
 {
   if (planeGeometry == nullptr)
     return -1;
 
   us::ServiceReference<PlanePositionManagerService> serviceRef =
     us::GetModuleContext()->GetServiceReference<PlanePositionManagerService>();
   PlanePositionManagerService *service = us::GetModuleContext()->GetService(serviceRef);
 
   unsigned int size = service->GetNumberOfPlanePositions();
   unsigned int id = service->AddNewPlanePosition(planeGeometry, sliceIndex);
 
   mitk::PlanarCircle::Pointer contourMarker = mitk::PlanarCircle::New();
   mitk::Point2D p1;
   planeGeometry->Map(planeGeometry->GetCenter(), p1);
   contourMarker->SetPlaneGeometry(planeGeometry->Clone());
   contourMarker->PlaceFigure(p1);
   contourMarker->SetCurrentControlPoint(p1);
   contourMarker->SetProperty("initiallyplaced", mitk::BoolProperty::New(true));
 
   std::stringstream markerStream;
   auto workingNode = this->GetWorkingDataNode();
 
   markerStream << m_Contourmarkername;
   markerStream << " ";
   markerStream << id + 1;
 
   DataNode::Pointer rotatedContourNode = DataNode::New();
 
   rotatedContourNode->SetData(contourMarker);
   rotatedContourNode->SetProperty("name", StringProperty::New(markerStream.str()));
   rotatedContourNode->SetProperty("isContourMarker", BoolProperty::New(true));
   rotatedContourNode->SetBoolProperty("PlanarFigureInitializedWindow", true, m_LastEventSender);
   rotatedContourNode->SetProperty("includeInBoundingBox", BoolProperty::New(false));
   rotatedContourNode->SetProperty("helper object", mitk::BoolProperty::New(!m_ShowMarkerNodes));
   rotatedContourNode->SetProperty("planarfigure.drawcontrolpoints", BoolProperty::New(false));
   rotatedContourNode->SetProperty("planarfigure.drawname", BoolProperty::New(false));
   rotatedContourNode->SetProperty("planarfigure.drawoutline", BoolProperty::New(false));
   rotatedContourNode->SetProperty("planarfigure.drawshadow", BoolProperty::New(false));
 
   if (planeGeometry)
   {
     if (id == size)
     {
       this->GetToolManager()->GetDataStorage()->Add(rotatedContourNode, workingNode);
     }
     else
     {
       mitk::NodePredicateProperty::Pointer isMarker =
         mitk::NodePredicateProperty::New("isContourMarker", mitk::BoolProperty::New(true));
 
       mitk::DataStorage::SetOfObjects::ConstPointer markers =
         this->GetToolManager()->GetDataStorage()->GetDerivations(workingNode, isMarker);
 
       for (auto iter = markers->begin(); iter != markers->end(); ++iter)
       {
         std::string nodeName = (*iter)->GetName();
         unsigned int t = nodeName.find_last_of(" ");
         unsigned int markerId = atof(nodeName.substr(t + 1).c_str()) - 1;
         if (id == markerId)
         {
           return id;
         }
       }
       this->GetToolManager()->GetDataStorage()->Add(rotatedContourNode, workingNode);
     }
   }
   return id;
 }
 
 void mitk::SegTool2D::InteractiveSegmentationBugMessage(const std::string &message) const
 {
   MITK_ERROR << "********************************************************************************" << std::endl
              << " " << message << std::endl
              << "********************************************************************************" << std::endl
              << "  " << std::endl
              << " If your image is rotated or the 2D views don't really contain the patient image, try to press the "
                 "button next to the image selection. "
              << std::endl
              << "  " << std::endl
              << " Please file a BUG REPORT: " << std::endl
              << " https://phabricator.mitk.org/" << std::endl
              << " Contain the following information:" << std::endl
              << "  - What image were you working on?" << std::endl
              << "  - Which region of the image?" << std::endl
              << "  - Which tool did you use?" << std::endl
              << "  - What did you do?" << std::endl
              << "  - What happened (not)? What did you expect?" << std::endl;
 }
 
 void mitk::SegTool2D::WritePreviewOnWorkingImage(
   Image *targetSlice, const Image *sourceSlice, const Image *workingImage, int paintingPixelValue)
 {
   if (nullptr == targetSlice)
   {
     mitkThrow() << "Cannot write preview on working image. Target slice does not point to a valid instance.";
   }
 
   if (nullptr == sourceSlice)
   {
     mitkThrow() << "Cannot write preview on working image. Source slice does not point to a valid instance.";
   }
 
   if (nullptr == workingImage)
   {
     mitkThrow() << "Cannot write preview on working image. Working image does not point to a valid instance.";
   }
 
   auto constVtkSource = sourceSlice->GetVtkImageData();
   /*Need to const cast because Vtk interface does not support const correctly.
    (or I am not experienced enough to use it correctly)*/
   auto nonConstVtkSource = const_cast<vtkImageData*>(constVtkSource);
 
   ContourModelUtils::FillSliceInSlice(nonConstVtkSource, targetSlice->GetVtkImageData(), workingImage, paintingPixelValue, 1.0);
 }
 
 bool mitk::SegTool2D::IsPositionEventInsideImageRegion(mitk::InteractionPositionEvent* positionEvent,
   const mitk::BaseData* data)
 {
   bool isPositionEventInsideImageRegion =
     nullptr != data && data->GetGeometry()->IsInside(positionEvent->GetPositionInWorld());
 
   if (!isPositionEventInsideImageRegion)
     MITK_WARN("EditableContourTool") << "PositionEvent is outside ImageRegion!";
 
   return isPositionEventInsideImageRegion;
 }
diff --git a/Modules/Segmentation/Interactions/mitkSegWithPreviewTool.cpp b/Modules/Segmentation/Interactions/mitkSegWithPreviewTool.cpp
index 77ffb417cd..b35e7c9129 100644
--- a/Modules/Segmentation/Interactions/mitkSegWithPreviewTool.cpp
+++ b/Modules/Segmentation/Interactions/mitkSegWithPreviewTool.cpp
@@ -1,842 +1,839 @@
 /*============================================================================
 
 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 "mitkSegWithPreviewTool.h"
 
 #include "mitkToolManager.h"
 
 #include "mitkColorProperty.h"
 #include "mitkProperties.h"
 
 #include "mitkDataStorage.h"
 #include "mitkRenderingManager.h"
 #include <mitkTimeNavigationController.h>
 
 #include "mitkImageAccessByItk.h"
 #include "mitkImageCast.h"
 #include "mitkLabelSetImage.h"
 #include "mitkMaskAndCutRoiImageFilter.h"
 #include "mitkPadImageFilter.h"
 #include "mitkNodePredicateGeometry.h"
 #include "mitkSegTool2D.h"
 
 mitk::SegWithPreviewTool::SegWithPreviewTool(bool lazyDynamicPreviews): Tool("dummy"), m_LazyDynamicPreviews(lazyDynamicPreviews)
 {
   m_ProgressCommand = ToolCommand::New();
 }
 
 mitk::SegWithPreviewTool::SegWithPreviewTool(bool lazyDynamicPreviews, const char* interactorType, const us::Module* interactorModule) : Tool(interactorType, interactorModule), m_LazyDynamicPreviews(lazyDynamicPreviews)
 {
   m_ProgressCommand = ToolCommand::New();
 }
 
 mitk::SegWithPreviewTool::~SegWithPreviewTool()
 {
 }
 
 void mitk::SegWithPreviewTool::SetMergeStyle(MultiLabelSegmentation::MergeStyle mergeStyle)
 {
   m_MergeStyle = mergeStyle;
   this->Modified();
 }
 
 void mitk::SegWithPreviewTool::SetOverwriteStyle(MultiLabelSegmentation::OverwriteStyle overwriteStyle)
 {
   m_OverwriteStyle = overwriteStyle;
   this->Modified();
 }
 
 void mitk::SegWithPreviewTool::SetLabelTransferScope(LabelTransferScope labelTransferScope)
 {
   m_LabelTransferScope = labelTransferScope;
   this->Modified();
 }
 
 void mitk::SegWithPreviewTool::SetLabelTransferMode(LabelTransferMode labelTransferMode)
 {
   m_LabelTransferMode = labelTransferMode;
   this->Modified();
 }
 
 void mitk::SegWithPreviewTool::SetSelectedLabels(const SelectedLabelVectorType& labelsToTransfer)
 {
   m_SelectedLabels = labelsToTransfer;
   this->Modified();
 }
 
 bool mitk::SegWithPreviewTool::CanHandle(const BaseData* referenceData, const BaseData* workingData) const
 {
   if (!Superclass::CanHandle(referenceData, workingData))
     return false;
 
   if (workingData == nullptr)
     return false;
 
   auto* referenceImage = dynamic_cast<const Image*>(referenceData);
   if (referenceImage == nullptr)
     return false;
 
   auto* labelSet = dynamic_cast<const LabelSetImage*>(workingData);
   if (labelSet != nullptr)
     return true;
 
   auto* workingImage = dynamic_cast<const Image*>(workingData);
   if (workingImage == nullptr)
     return false;
 
   // If the working image is a normal image and not a label set image
   // it must have the same pixel type as a label set.
   return MakeScalarPixelType< DefaultSegmentationDataType >() == workingImage->GetPixelType();
 }
 
 void mitk::SegWithPreviewTool::Activated()
 {
   Superclass::Activated();
 
   this->GetToolManager()->RoiDataChanged +=
     MessageDelegate<SegWithPreviewTool>(this, &SegWithPreviewTool::OnRoiDataChanged);
 
   this->GetToolManager()->SelectedTimePointChanged +=
     MessageDelegate<SegWithPreviewTool>(this, &SegWithPreviewTool::OnTimePointChanged);
 
   m_ReferenceDataNode = this->GetToolManager()->GetReferenceData(0);
   m_SegmentationInputNode = m_ReferenceDataNode;
 
   m_LastTimePointOfUpdate = RenderingManager::GetInstance()->GetTimeNavigationController()->GetSelectedTimePoint();
 
   if (m_PreviewSegmentationNode.IsNull())
   {
     m_PreviewSegmentationNode = DataNode::New();
     m_PreviewSegmentationNode->SetProperty("color", ColorProperty::New(0.0, 1.0, 0.0));
     m_PreviewSegmentationNode->SetProperty("name", StringProperty::New(std::string(this->GetName())+" preview"));
     m_PreviewSegmentationNode->SetProperty("opacity", FloatProperty::New(0.3));
     m_PreviewSegmentationNode->SetProperty("binary", BoolProperty::New(true));
     m_PreviewSegmentationNode->SetProperty("helper object", BoolProperty::New(true));
   }
 
   if (m_SegmentationInputNode.IsNotNull())
   {
     this->ResetPreviewNode();
     this->InitiateToolByInput();
   }
   else
   {
     this->GetToolManager()->ActivateTool(-1);
   }
 }
 
 void mitk::SegWithPreviewTool::Deactivated()
 {
   this->GetToolManager()->RoiDataChanged -=
     MessageDelegate<SegWithPreviewTool>(this, &SegWithPreviewTool::OnRoiDataChanged);
 
   this->GetToolManager()->SelectedTimePointChanged -=
     MessageDelegate<SegWithPreviewTool>(this, &SegWithPreviewTool::OnTimePointChanged);
 
   m_SegmentationInputNode = nullptr;
   m_ReferenceDataNode = nullptr;
   m_WorkingPlaneGeometry = nullptr;
 
   try
   {
     if (DataStorage *storage = this->GetToolManager()->GetDataStorage())
     {
       storage->Remove(m_PreviewSegmentationNode);
       RenderingManager::GetInstance()->RequestUpdateAll();
     }
   }
   catch (...)
   {
     // don't care
   }
 
   if (m_PreviewSegmentationNode.IsNotNull())
   {
     m_PreviewSegmentationNode->SetData(nullptr);
   }
 
   Superclass::Deactivated();
 }
 
 void mitk::SegWithPreviewTool::ConfirmSegmentation()
 {
   bool labelChanged = this->EnsureUpToDateUserDefinedActiveLabel();
   if ((m_LazyDynamicPreviews && m_CreateAllTimeSteps) || labelChanged)
   { // The tool should create all time steps but is currently in lazy mode,
     // thus ensure that a preview for all time steps is available.
     this->UpdatePreview(true);
   }
 
   CreateResultSegmentationFromPreview();
 
   RenderingManager::GetInstance()->RequestUpdateAll();
 
   if (!m_KeepActiveAfterAccept)
   {
     this->GetToolManager()->ActivateTool(-1);
   }
   this->ConfirmCleanUp();
 }
 
 void  mitk::SegWithPreviewTool::InitiateToolByInput()
 {
   //default implementation does nothing.
   //implement in derived classes to change behavior
 }
 
 mitk::LabelSetImage* mitk::SegWithPreviewTool::GetPreviewSegmentation()
 {
   if (m_PreviewSegmentationNode.IsNull())
   {
     return nullptr;
   }
 
   return dynamic_cast<LabelSetImage*>(m_PreviewSegmentationNode->GetData());
 }
 
 const mitk::LabelSetImage* mitk::SegWithPreviewTool::GetPreviewSegmentation() const
 {
   if (m_PreviewSegmentationNode.IsNull())
   {
     return nullptr;
   }
 
   return dynamic_cast<LabelSetImage*>(m_PreviewSegmentationNode->GetData());
 }
 
 mitk::DataNode* mitk::SegWithPreviewTool::GetPreviewSegmentationNode()
 {
   return m_PreviewSegmentationNode;
 }
 
 const mitk::Image* mitk::SegWithPreviewTool::GetSegmentationInput() const
 {
   if (m_SegmentationInputNode.IsNull())
   {
     return nullptr;
   }
 
   return dynamic_cast<const Image*>(m_SegmentationInputNode->GetData());
 }
 
 const mitk::Image* mitk::SegWithPreviewTool::GetReferenceData() const
 {
   if (m_ReferenceDataNode.IsNull())
   {
     return nullptr;
   }
 
   return dynamic_cast<const Image*>(m_ReferenceDataNode->GetData());
 }
 
 template <typename ImageType>
 void ClearBufferProcessing(ImageType* itkImage)
 {
   itkImage->FillBuffer(0);
 }
 
 void mitk::SegWithPreviewTool::ResetPreviewContentAtTimeStep(unsigned int timeStep)
 {
   auto previewImage = GetImageByTimeStep(this->GetPreviewSegmentation(), timeStep);
   if (nullptr != previewImage)
   {
     AccessByItk(previewImage, ClearBufferProcessing);
   }
 }
 
 void mitk::SegWithPreviewTool::ResetPreviewContent()
 {
   auto previewImage = this->GetPreviewSegmentation();
   if (nullptr != previewImage)
   {
     auto castedPreviewImage =
       dynamic_cast<LabelSetImage*>(previewImage);
     if (nullptr == castedPreviewImage) mitkThrow() << "Application is on wrong state / invalid tool implementation. Preview image should always be of type LabelSetImage now.";
     castedPreviewImage->ClearBuffer();
   }
 }
 
 void mitk::SegWithPreviewTool::ResetPreviewNode()
 {
   if (m_IsUpdating)
   {
     mitkThrow() << "Used tool is implemented incorrectly. ResetPreviewNode is called while preview update is ongoing. Check implementation!";
   }
 
   itk::RGBPixel<float> previewColor;
   previewColor[0] = 0.0f;
   previewColor[1] = 1.0f;
   previewColor[2] = 0.0f;
 
   const auto image = this->GetSegmentationInput();
   if (nullptr != image)
   {
     LabelSetImage::ConstPointer workingImage =
       dynamic_cast<const LabelSetImage *>(this->GetToolManager()->GetWorkingData(0)->GetData());
 
     if (workingImage.IsNotNull())
     {
       auto newPreviewImage = workingImage->Clone();
       if (this->GetResetsToEmptyPreview())
       {
         newPreviewImage->ClearBuffer();
       }
 
       if (newPreviewImage.IsNull())
       {
         MITK_ERROR << "Cannot create preview helper objects. Unable to clone working image";
         return;
       }
 
       m_PreviewSegmentationNode->SetData(newPreviewImage);
 
-      auto* activeLabelSet = newPreviewImage->GetActiveLabelSet();
-      if (nullptr == activeLabelSet)
+      if (newPreviewImage->GetNumberOfLayers() == 0)
       {
         newPreviewImage->AddLayer();
-        activeLabelSet = newPreviewImage->GetActiveLabelSet();
       }
 
-      auto* activeLabel = activeLabelSet->GetActiveLabel();
+      auto* activeLabel = newPreviewImage->GetActiveLabel();
       if (nullptr == activeLabel)
       {
-        activeLabel = activeLabelSet->AddLabel("toolresult", previewColor);
-        activeLabelSet = newPreviewImage->GetActiveLabelSet();
-        activeLabelSet->UpdateLookupTable(activeLabel->GetValue());
+        activeLabel = newPreviewImage->AddLabel("toolresult", previewColor, newPreviewImage->GetActiveLayer());
+        newPreviewImage->UpdateLookupTable(activeLabel->GetValue());
       }
       else if (m_UseSpecialPreviewColor)
       {
         // Let's paint the feedback node green...
         activeLabel->SetColor(previewColor);
-        activeLabelSet->UpdateLookupTable(activeLabel->GetValue());
+        newPreviewImage->UpdateLookupTable(activeLabel->GetValue());
       }
       activeLabel->SetVisible(true);
     }
     else
     {
       Image::ConstPointer workingImageBin = dynamic_cast<const Image*>(this->GetToolManager()->GetWorkingData(0)->GetData());
       if (workingImageBin.IsNotNull())
       {
         Image::Pointer newPreviewImage;
         if (this->GetResetsToEmptyPreview())
         {
           newPreviewImage = Image::New();
           newPreviewImage->Initialize(workingImageBin);
         }
         else
         {
           auto newPreviewImage = workingImageBin->Clone();
         }
         if (newPreviewImage.IsNull())
         {
           MITK_ERROR << "Cannot create preview helper objects. Unable to clone working image";
           return;
         }
         m_PreviewSegmentationNode->SetData(newPreviewImage);
       }
       else
       {
         mitkThrow() << "Tool is an invalid state. Cannot setup preview node. Working data is an unsupported class and should have not been accepted by CanHandle().";
       }
     }
 
     m_PreviewSegmentationNode->SetColor(previewColor);
     m_PreviewSegmentationNode->SetOpacity(0.5);
 
     int layer(50);
     m_ReferenceDataNode->GetIntProperty("layer", layer);
     m_PreviewSegmentationNode->SetIntProperty("layer", layer + 1);
 
     if (DataStorage *ds = this->GetToolManager()->GetDataStorage())
     {
       if (!ds->Exists(m_PreviewSegmentationNode))
         ds->Add(m_PreviewSegmentationNode, m_ReferenceDataNode);
     }
   }
 }
 
 mitk::SegWithPreviewTool::LabelMappingType mitk::SegWithPreviewTool::GetLabelMapping() const
 {
   LabelSetImage::LabelValueType offset = 0;
   
   if (LabelTransferMode::AddLabel == m_LabelTransferMode && LabelTransferScope::ActiveLabel!=m_LabelTransferScope)
   {
     //If we are not just working on active label and transfer mode is add, we need to compute an offset for adding the
     //preview labels instat of just mapping them to existing segmentation labels.
     const auto segmentation = this->GetTargetSegmentation();
     if (nullptr == segmentation)
       mitkThrow() << "Invalid state of SegWithPreviewTool. Cannot GetLabelMapping if no target segmentation is set.";
 
     auto labels = segmentation->GetLabels();
     auto maxLabelIter = std::max_element(std::begin(labels), std::end(labels), [](const Label::Pointer& a, const Label::Pointer& b) {
       return a->GetValue() < b->GetValue();
     });
 
     if (maxLabelIter != labels.end())
     {
       offset = maxLabelIter->GetPointer()->GetValue();
     }
   }
 
   LabelMappingType labelMapping = {};
 
   switch (this->m_LabelTransferScope)
   {
     case LabelTransferScope::SelectedLabels:
       {
         for (auto label : this->m_SelectedLabels)
         {
           labelMapping.push_back({label, label + offset});
         }
       }
       break;
     case LabelTransferScope::AllLabels:
       {
-        const auto labelSet = this->GetPreviewSegmentation()->GetActiveLabelSet();
-        for (auto labelIter = labelSet->IteratorConstBegin(); labelIter != labelSet->IteratorConstEnd(); ++labelIter)
+        const auto labelValues = this->GetPreviewSegmentation()->GetLabelValuesByGroup(this->GetPreviewSegmentation()->GetActiveLayer());
+        for (auto labelValue : labelValues)
         {
-        labelMapping.push_back({labelIter->second->GetValue(), labelIter->second->GetValue() + offset});
+        labelMapping.push_back({ labelValue, labelValue + offset});
         }
       }
       break;
     default:
       {
         if (m_SelectedLabels.empty())
           mitkThrow() << "Failed to generate label transfer mapping. Tool is in an invalid state, as "
                          "LabelTransferScope==ActiveLabel but no label is indicated as selected label. Check "
                          "implementation of derived tool class.";
         if (m_SelectedLabels.size() > 1)
         mitkThrow() << "Failed to generate label transfer mapping. Tool is in an invalid state, as "
                        "LabelTransferScope==ActiveLabel but more then one selected label is indicated."
                        "Should be only one. Check implementation of derived tool class.";
         labelMapping.push_back({m_SelectedLabels.front(), this->GetUserDefinedActiveLabel()});
       }
       break;
   }
 
   return labelMapping;
 }
 
 void mitk::SegWithPreviewTool::TransferImageAtTimeStep(const Image* sourceImage, Image* destinationImage, const TimeStepType timeStep, const LabelMappingType& labelMapping)
 {
   try
   {
     Image::ConstPointer sourceImageAtTimeStep = this->GetImageByTimeStep(sourceImage, timeStep);
 
     if (sourceImageAtTimeStep->GetPixelType() != destinationImage->GetPixelType())
     {
       mitkThrow() << "Cannot transfer images. Tool is in an invalid state, source image and destination image do not have the same pixel type. "
         << "Source pixel type: " << sourceImage->GetPixelType().GetTypeAsString()
         << "; destination pixel type: " << destinationImage->GetPixelType().GetTypeAsString();
     }
 
     if (!Equal(*(sourceImage->GetGeometry(timeStep)), *(destinationImage->GetGeometry(timeStep)), NODE_PREDICATE_GEOMETRY_DEFAULT_CHECK_COORDINATE_PRECISION, NODE_PREDICATE_GEOMETRY_DEFAULT_CHECK_DIRECTION_PRECISION, false))
     {
       mitkThrow() << "Cannot transfer images. Tool is in an invalid state, source image and destination image do not have the same geometry.";
     }
 
     if (nullptr != this->GetWorkingPlaneGeometry())
     {
       auto sourceSlice = SegTool2D::GetAffectedImageSliceAs2DImage(this->GetWorkingPlaneGeometry(), sourceImage, timeStep);
       auto resultSlice =
         SegTool2D::GetAffectedImageSliceAs2DImage(this->GetWorkingPlaneGeometry(), destinationImage, timeStep)->Clone();
       auto destLSImage = dynamic_cast<LabelSetImage *>(destinationImage);
       //We need to transfer explictly to a copy of the current working image to ensure that labelMapping is done and things
       //like merge style, overwrite style and locks are regarded.
       TransferLabelContentAtTimeStep(sourceSlice,
                                      resultSlice,
-                                     destLSImage->GetActiveLabelSet(),
+                                     destLSImage->GetConstLabelsByValue(destLSImage->GetLabelValuesByGroup(destLSImage->GetActiveLayer())),
                                      timeStep,
                                      0,
                                      0,
                                      destLSImage->GetUnlabeledLabelLock(),
                                      labelMapping,
                                      m_MergeStyle,
                                      m_OverwriteStyle);
       //We use WriteBackSegmentationResult to ensure undo/redo is supported also by derived tools of this class.
       SegTool2D::WriteBackSegmentationResult(this->GetTargetSegmentationNode(), m_WorkingPlaneGeometry, resultSlice, timeStep);
     }
     else
     { //take care of the full segmentation volume
       auto sourceLSImage = dynamic_cast<const LabelSetImage*>(sourceImage);
       auto destLSImage = dynamic_cast<LabelSetImage*>(destinationImage);
 
       TransferLabelContentAtTimeStep(sourceLSImage, destLSImage, timeStep, labelMapping, m_MergeStyle, m_OverwriteStyle);
     }
   }
   catch (mitk::Exception& e)
   {
     Tool::ErrorMessage(e.GetDescription());
     mitkReThrow(e);
   }
 }
 
 void mitk::SegWithPreviewTool::CreateResultSegmentationFromPreview()
 {
   const auto segInput = this->GetSegmentationInput();
   auto previewImage = this->GetPreviewSegmentation();
   if (nullptr != segInput && nullptr != previewImage)
   {
     DataNode::Pointer resultSegmentationNode = GetTargetSegmentationNode();
 
     if (resultSegmentationNode.IsNotNull())
     {
       const TimePointType timePoint = RenderingManager::GetInstance()->GetTimeNavigationController()->GetSelectedTimePoint();
       auto resultSegmentation = dynamic_cast<Image*>(resultSegmentationNode->GetData());
 
       // REMARK: the following code in this scope assumes that previewImage and resultSegmentation
       // are clones of the working referenceImage (segmentation provided to the tool). Therefore they have
       // the same time geometry.
       if (previewImage->GetTimeSteps() != resultSegmentation->GetTimeSteps())
       {
         mitkThrow() << "Cannot confirm/transfer segmentation. Internal tool state is invalid."
           << " Preview segmentation and segmentation result image have different time geometries.";
       }
 
       auto labelMapping = this->GetLabelMapping();
       this->PreparePreviewToResultTransfer(labelMapping);
       if (m_CreateAllTimeSteps)
       {
         for (unsigned int timeStep = 0; timeStep < previewImage->GetTimeSteps(); ++timeStep)
         {
           this->TransferImageAtTimeStep(previewImage, resultSegmentation, timeStep, labelMapping);
         }
       }
       else
       {
         const auto timeStep = resultSegmentation->GetTimeGeometry()->TimePointToTimeStep(timePoint);
         this->TransferImageAtTimeStep(previewImage, resultSegmentation, timeStep, labelMapping);
       }
 
       // since we are maybe working on a smaller referenceImage, pad it to the size of the original referenceImage
       if (m_ReferenceDataNode.GetPointer() != m_SegmentationInputNode.GetPointer())
       {
         PadImageFilter::Pointer padFilter = PadImageFilter::New();
 
         padFilter->SetInput(0, resultSegmentation);
         padFilter->SetInput(1, dynamic_cast<Image*>(m_ReferenceDataNode->GetData()));
         padFilter->SetBinaryFilter(true);
         padFilter->SetUpperThreshold(1);
         padFilter->SetLowerThreshold(1);
         padFilter->Update();
 
         resultSegmentationNode->SetData(padFilter->GetOutput());
       }
       this->EnsureTargetSegmentationNodeInDataStorage();
     }
   }
 }
 
 void mitk::SegWithPreviewTool::OnRoiDataChanged()
 {
   DataNode::ConstPointer node = this->GetToolManager()->GetRoiData(0);
 
   if (node.IsNotNull())
   {
     MaskAndCutRoiImageFilter::Pointer roiFilter = MaskAndCutRoiImageFilter::New();
     Image::Pointer image = dynamic_cast<Image *>(m_SegmentationInputNode->GetData());
 
     if (image.IsNull())
       return;
 
     roiFilter->SetInput(image);
     roiFilter->SetRegionOfInterest(node->GetData());
     roiFilter->Update();
 
     DataNode::Pointer tmpNode = DataNode::New();
     tmpNode->SetData(roiFilter->GetOutput());
 
     m_SegmentationInputNode = tmpNode;
   }
   else
     m_SegmentationInputNode = m_ReferenceDataNode;
 
   this->ResetPreviewNode();
   this->InitiateToolByInput();
   this->UpdatePreview();
 }
 
 void mitk::SegWithPreviewTool::OnTimePointChanged()
 {
   if (m_IsTimePointChangeAware && m_PreviewSegmentationNode.IsNotNull() && m_SegmentationInputNode.IsNotNull())
   {
     const TimePointType timePoint = RenderingManager::GetInstance()->GetTimeNavigationController()->GetSelectedTimePoint();
 
     const bool isStaticSegOnDynamicImage = m_PreviewSegmentationNode->GetData()->GetTimeSteps() == 1 && m_SegmentationInputNode->GetData()->GetTimeSteps() > 1;
     if (timePoint!=m_LastTimePointOfUpdate && (isStaticSegOnDynamicImage || m_LazyDynamicPreviews))
     { //we only need to update either because we are lazzy
       //or because we have a static segmentation with a dynamic referenceImage 
       this->UpdatePreview();
     }
   }
 }
 
 bool mitk::SegWithPreviewTool::EnsureUpToDateUserDefinedActiveLabel()
 {
   bool labelChanged = true;
 
   const auto workingImage = dynamic_cast<const Image*>(this->GetToolManager()->GetWorkingData(0)->GetData());
   if (const auto& labelSetImage = dynamic_cast<const LabelSetImage*>(workingImage))
   {
     // this is a fix for T28131 / T28986, which should be refactored if T28524 is being worked on
-    auto newLabel = labelSetImage->GetActiveLabel(labelSetImage->GetActiveLayer())->GetValue();
+    auto newLabel = labelSetImage->GetActiveLabel()->GetValue();
     labelChanged = newLabel != m_UserDefinedActiveLabel;
     m_UserDefinedActiveLabel = newLabel;
   }
   else
   {
     m_UserDefinedActiveLabel = 1;
     labelChanged = false;
   }
   return labelChanged;
 }
 
 void mitk::SegWithPreviewTool::UpdatePreview(bool ignoreLazyPreviewSetting)
 {
   const auto inputImage = this->GetSegmentationInput();
   auto previewImage = this->GetPreviewSegmentation();
   int progress_steps = 200;
 
   const auto workingImage = dynamic_cast<const Image*>(this->GetToolManager()->GetWorkingData(0)->GetData());
   this->EnsureUpToDateUserDefinedActiveLabel();
 
   this->CurrentlyBusy.Send(true);
   m_IsUpdating = true;
 
   this->UpdatePrepare();
 
   const TimePointType timePoint = RenderingManager::GetInstance()->GetTimeNavigationController()->GetSelectedTimePoint();
 
   try
   {
     if (nullptr != inputImage && nullptr != previewImage)
     {
       m_ProgressCommand->AddStepsToDo(progress_steps);
 
       if (previewImage->GetTimeSteps() > 1 && (ignoreLazyPreviewSetting || !m_LazyDynamicPreviews))
       {
         for (unsigned int timeStep = 0; timeStep < previewImage->GetTimeSteps(); ++timeStep)
         {
           Image::ConstPointer feedBackImage;
           Image::ConstPointer currentSegImage;
 
           auto previewTimePoint = previewImage->GetTimeGeometry()->TimeStepToTimePoint(timeStep);
           auto inputTimeStep = inputImage->GetTimeGeometry()->TimePointToTimeStep(previewTimePoint);
 
           if (nullptr != this->GetWorkingPlaneGeometry())
           { //only extract a specific slice defined by the working plane as feedback referenceImage.
             feedBackImage = SegTool2D::GetAffectedImageSliceAs2DImage(this->GetWorkingPlaneGeometry(), inputImage, inputTimeStep);
             currentSegImage = SegTool2D::GetAffectedImageSliceAs2DImageByTimePoint(this->GetWorkingPlaneGeometry(), workingImage, previewTimePoint);
           }
           else
           { //work on the whole feedback referenceImage
             feedBackImage = this->GetImageByTimeStep(inputImage, inputTimeStep);
             currentSegImage = this->GetImageByTimePoint(workingImage, previewTimePoint);
           }
 
           this->DoUpdatePreview(feedBackImage, currentSegImage, previewImage, timeStep);
         }
       }
       else
       {
         Image::ConstPointer feedBackImage;
         Image::ConstPointer currentSegImage;
 
         if (nullptr != this->GetWorkingPlaneGeometry())
         {
           feedBackImage = SegTool2D::GetAffectedImageSliceAs2DImageByTimePoint(this->GetWorkingPlaneGeometry(), inputImage, timePoint);
           currentSegImage = SegTool2D::GetAffectedImageSliceAs2DImageByTimePoint(this->GetWorkingPlaneGeometry(), workingImage, timePoint);
         }
         else
         {
           feedBackImage = this->GetImageByTimePoint(inputImage, timePoint);
           currentSegImage = this->GetImageByTimePoint(workingImage, timePoint);
         }
 
         auto timeStep = previewImage->GetTimeGeometry()->TimePointToTimeStep(timePoint);
 
         this->DoUpdatePreview(feedBackImage, currentSegImage, previewImage, timeStep);
       }
       RenderingManager::GetInstance()->RequestUpdateAll();
     }
   }
   catch (itk::ExceptionObject & excep)
   {
     MITK_ERROR << "Exception caught: " << excep.GetDescription();
 
     m_ProgressCommand->SetProgress(progress_steps);
 
     std::string msg = excep.GetDescription();
     ErrorMessage.Send(msg);
   }
   catch (...)
   {
     m_ProgressCommand->SetProgress(progress_steps);
     m_IsUpdating = false;
     CurrentlyBusy.Send(false);
     throw;
   }
 
   this->UpdateCleanUp();
   m_LastTimePointOfUpdate = timePoint;
   m_ProgressCommand->SetProgress(progress_steps);
   m_IsUpdating = false;
   CurrentlyBusy.Send(false);
 }
 
 bool mitk::SegWithPreviewTool::IsUpdating() const
 {
   return m_IsUpdating;
 }
 
 void mitk::SegWithPreviewTool::UpdatePrepare()
 {
   // default implementation does nothing
   //reimplement in derived classes for special behavior
 }
 
 void mitk::SegWithPreviewTool::UpdateCleanUp()
 {
   // default implementation does nothing
   //reimplement in derived classes for special behavior
 }
 
 void mitk::SegWithPreviewTool::ConfirmCleanUp()
 {
   // default implementation does nothing
   // reimplement in derived classes for special behavior
 }
 
 void mitk::SegWithPreviewTool::TransferLabelInformation(const LabelMappingType& labelMapping,
   const mitk::LabelSetImage* source, mitk::LabelSetImage* target)
 {
   for (const auto& [sourceLabel, targetLabel] : labelMapping)
   {
     if (LabelSetImage::UnlabeledValue != sourceLabel &&
         LabelSetImage::UnlabeledValue != targetLabel &&
         !target->ExistLabel(targetLabel, target->GetActiveLayer()))
     {
       if (!source->ExistLabel(sourceLabel, source->GetActiveLayer()))
       {
         mitkThrow() << "Cannot prepare segmentation for preview transfer. Preview seems invalid as label is missing. Missing label: " << sourceLabel;
       }
 
       auto clonedLabel = source->GetLabel(sourceLabel)->Clone();
       clonedLabel->SetValue(targetLabel);
-      target->GetActiveLabelSet()->AddLabel(clonedLabel);
+      target->AddLabel(clonedLabel,target->GetActiveLayer(), false, false);
     }
   }
 }
 
 void mitk::SegWithPreviewTool::PreparePreviewToResultTransfer(const LabelMappingType& labelMapping)
 {
   DataNode::Pointer resultSegmentationNode = GetTargetSegmentationNode();
 
   if (resultSegmentationNode.IsNotNull())
   {
     auto resultSegmentation = dynamic_cast<LabelSetImage*>(resultSegmentationNode->GetData());
 
     if (nullptr == resultSegmentation)
     {
       mitkThrow() << "Cannot prepare segmentation for preview transfer. Tool is in invalid state as segmentation is not existing or of right type";
     }
 
     auto preview = this->GetPreviewSegmentation();
     TransferLabelInformation(labelMapping, preview, resultSegmentation);
   }
 }
 
 mitk::TimePointType mitk::SegWithPreviewTool::GetLastTimePointOfUpdate() const
 {
   return m_LastTimePointOfUpdate;
 }
 
 mitk::LabelSetImage::LabelValueType mitk::SegWithPreviewTool::GetActiveLabelValueOfPreview() const
 {
   const auto previewImage = this->GetPreviewSegmentation();
-  const auto activeLabel = previewImage->GetActiveLabel(previewImage->GetActiveLayer());
+  const auto activeLabel = previewImage->GetActiveLabel();
   if (nullptr == activeLabel)
     mitkThrow() << this->GetNameOfClass() <<" is in an invalid state, as "
                    "preview has no active label indicated. Check "
                    "implementation of the class.";
 
   return activeLabel->GetValue();
 }
 
 const char* mitk::SegWithPreviewTool::GetGroup() const
 {
   return "autoSegmentation";
 }
 
 mitk::Image::ConstPointer mitk::SegWithPreviewTool::GetImageByTimeStep(const mitk::Image* image, TimeStepType timestep)
 {
   return SelectImageByTimeStep(image, timestep);
 }
 
 mitk::Image::Pointer mitk::SegWithPreviewTool::GetImageByTimeStep(mitk::Image* image, TimeStepType timestep)
 {
   return SelectImageByTimeStep(image, timestep);
 }
 
 mitk::Image::ConstPointer mitk::SegWithPreviewTool::GetImageByTimePoint(const mitk::Image* image, TimePointType timePoint)
 {
   return SelectImageByTimePoint(image, timePoint);
 }
 
 void mitk::SegWithPreviewTool::EnsureTargetSegmentationNodeInDataStorage() const
 {
   auto targetNode = this->GetTargetSegmentationNode();
   auto dataStorage = this->GetToolManager()->GetDataStorage();
   if (!dataStorage->Exists(targetNode))
   {
     dataStorage->Add(targetNode, this->GetToolManager()->GetReferenceData(0));
   }
 }
 
 std::string mitk::SegWithPreviewTool::GetCurrentSegmentationName()
 {
   auto workingData = this->GetToolManager()->GetWorkingData(0);
 
   return nullptr != workingData
     ? workingData->GetName()
     : "";
 }
 
 mitk::DataNode* mitk::SegWithPreviewTool::GetTargetSegmentationNode() const
 {
   return this->GetToolManager()->GetWorkingData(0);
 }
 
 mitk::LabelSetImage* mitk::SegWithPreviewTool::GetTargetSegmentation() const
 {
   auto node = this->GetTargetSegmentationNode();
 
   if (nullptr == node)
     return nullptr;
 
   return dynamic_cast<LabelSetImage*>(node->GetData());
 }
 
 void mitk::SegWithPreviewTool::TransferLabelSetImageContent(const LabelSetImage* source, LabelSetImage* target, TimeStepType timeStep)
 {
   mitk::ImageReadAccessor newMitkImgAcc(source);
 
   LabelMappingType labelMapping;
-  const auto labelSet = source->GetActiveLabelSet();
-  for (auto labelIter = labelSet->IteratorConstBegin(); labelIter != labelSet->IteratorConstEnd(); ++labelIter)
+  const auto labelValues = source->GetLabelValuesByGroup(source->GetActiveLayer());
+  for (const auto& labelValue : labelValues)
   {
-    labelMapping.push_back({ labelIter->second->GetValue(),labelIter->second->GetValue() });
+    labelMapping.push_back({ labelValue,labelValue });
   }
   TransferLabelInformation(labelMapping, source, target);
 
   target->SetVolume(newMitkImgAcc.GetData(), timeStep);
 }
diff --git a/Modules/Segmentation/Interactions/mitkTool.cpp b/Modules/Segmentation/Interactions/mitkTool.cpp
index 6ad70a18e1..ffe0955d82 100644
--- a/Modules/Segmentation/Interactions/mitkTool.cpp
+++ b/Modules/Segmentation/Interactions/mitkTool.cpp
@@ -1,338 +1,338 @@
 /*============================================================================
 
 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 "mitkTool.h"
 
 #include "mitkDisplayActionEventBroadcast.h"
 #include "mitkImageReadAccessor.h"
 #include "mitkImageWriteAccessor.h"
 #include "mitkLevelWindowProperty.h"
 #include "mitkLookupTableProperty.h"
 #include "mitkProperties.h"
 #include "mitkVtkResliceInterpolationProperty.h"
 #include <mitkDICOMSegmentationPropertyHelper.cpp>
 #include <mitkToolManager.h>
 
 // us
 #include <usGetModuleContext.h>
 #include <usModuleResource.h>
 
 // itk
 #include <itkObjectFactory.h>
 
 namespace mitk
 {
   itkEventMacroDefinition(ToolEvent, itk::ModifiedEvent);
 }
 
 mitk::Tool::Tool(const char *type, const us::Module *interactorModule)
   : m_EventConfig(""),
     m_ToolManager(nullptr),
     m_PredicateImages(NodePredicateDataType::New("Image")), // for reference images
     m_PredicateDim3(NodePredicateDimension::New(3, 1)),
     m_PredicateDim4(NodePredicateDimension::New(4, 1)),
     m_PredicateDimension(mitk::NodePredicateOr::New(m_PredicateDim3, m_PredicateDim4)),
     m_PredicateImage3D(NodePredicateAnd::New(m_PredicateImages, m_PredicateDimension)),
     m_PredicateBinary(NodePredicateProperty::New("binary", BoolProperty::New(true))),
     m_PredicateNotBinary(NodePredicateNot::New(m_PredicateBinary)),
     m_PredicateSegmentation(NodePredicateProperty::New("segmentation", BoolProperty::New(true))),
     m_PredicateNotSegmentation(NodePredicateNot::New(m_PredicateSegmentation)),
     m_PredicateHelper(NodePredicateProperty::New("helper object", BoolProperty::New(true))),
     m_PredicateNotHelper(NodePredicateNot::New(m_PredicateHelper)),
     m_PredicateImageColorful(NodePredicateAnd::New(m_PredicateNotBinary, m_PredicateNotSegmentation)),
     m_PredicateImageColorfulNotHelper(NodePredicateAnd::New(m_PredicateImageColorful, m_PredicateNotHelper)),
     m_PredicateReference(NodePredicateAnd::New(m_PredicateImage3D, m_PredicateImageColorfulNotHelper)),
     m_IsSegmentationPredicate(
       NodePredicateAnd::New(NodePredicateOr::New(m_PredicateBinary, m_PredicateSegmentation), m_PredicateNotHelper)),
     m_InteractorType(type),
     m_DisplayInteractionConfigs(),
     m_InteractorModule(interactorModule)
 {
 }
 
 mitk::Tool::~Tool()
 {
 }
 
 bool mitk::Tool::CanHandle(const BaseData* referenceData, const BaseData* /*workingData*/) const
 {
   if (referenceData == nullptr)
     return false;
 
   return true;
 }
 
 void mitk::Tool::InitializeStateMachine()
 {
   if (m_InteractorType.empty())
     return;
 
   try
   {
     auto isThisModule = nullptr == m_InteractorModule;
 
     auto module = isThisModule
       ? us::GetModuleContext()->GetModule()
       : m_InteractorModule;
 
     LoadStateMachine(m_InteractorType + ".xml", module);
     SetEventConfig(isThisModule ? "SegmentationToolsConfig.xml" : m_InteractorType + "Config.xml", module);
   }
   catch (const std::exception &e)
   {
     MITK_ERROR << "Could not load statemachine pattern " << m_InteractorType << ".xml with exception: " << e.what();
   }
 }
 
 void mitk::Tool::Notify(InteractionEvent *interactionEvent, bool isHandled)
 {
   // to use the state machine pattern,
   // the event is passed to the state machine interface to be handled
   if (!isHandled)
   {
     this->HandleEvent(interactionEvent, nullptr);
   }
 }
 
 void mitk::Tool::ConnectActionsAndFunctions()
 {
 }
 
 bool mitk::Tool::FilterEvents(InteractionEvent *, DataNode *)
 {
   return true;
 }
 
 const char *mitk::Tool::GetGroup() const
 {
   return "default";
 }
 
 void mitk::Tool::SetToolManager(ToolManager *manager)
 {
   m_ToolManager = manager;
 }
 
 mitk::ToolManager* mitk::Tool::GetToolManager() const
 {
   return m_ToolManager;
 }
 
 mitk::DataStorage* mitk::Tool::GetDataStorage() const
 {
   if (nullptr != m_ToolManager)
   {
     return m_ToolManager->GetDataStorage();
   }
   return nullptr;
 }
 
 void mitk::Tool::Activated()
 {
   // As a legacy solution the display interaction of the new interaction framework is disabled here to avoid conflicts
   // with tools
   // Note: this only affects InteractionEventObservers (formerly known as Listeners) all DataNode specific interaction
   // will still be enabled
   m_DisplayInteractionConfigs.clear();
   auto eventObservers = us::GetModuleContext()->GetServiceReferences<InteractionEventObserver>();
   for (const auto& eventObserver : eventObservers)
   {
     auto displayActionEventBroadcast = dynamic_cast<DisplayActionEventBroadcast*>(
       us::GetModuleContext()->GetService<InteractionEventObserver>(eventObserver));
     if (nullptr != displayActionEventBroadcast)
     {
       // remember the original configuration
       m_DisplayInteractionConfigs.insert(std::make_pair(eventObserver, displayActionEventBroadcast->GetEventConfig()));
       // here the alternative configuration is loaded
       displayActionEventBroadcast->AddEventConfig(m_EventConfig.c_str());
     }
   }
 }
 
 void mitk::Tool::Deactivated()
 {
   // Re-enabling InteractionEventObservers that have been previously disabled for legacy handling of Tools
   // in new interaction framework
   for (const auto& displayInteractionConfig : m_DisplayInteractionConfigs)
   {
     if (displayInteractionConfig.first)
     {
       auto displayActionEventBroadcast = static_cast<mitk::DisplayActionEventBroadcast*>(
         us::GetModuleContext()->GetService<mitk::InteractionEventObserver>(displayInteractionConfig.first));
 
       if (nullptr != displayActionEventBroadcast)
       {
         // here the regular configuration is loaded again
         displayActionEventBroadcast->SetEventConfig(displayInteractionConfig.second);
       }
     }
   }
 
   m_DisplayInteractionConfigs.clear();
 }
 
 itk::Object::Pointer mitk::Tool::GetGUI(const std::string &toolkitPrefix, const std::string &toolkitPostfix)
 {
   itk::Object::Pointer object;
 
   std::string classname = this->GetNameOfClass();
   std::string guiClassname = toolkitPrefix + classname + toolkitPostfix;
 
   std::list<itk::LightObject::Pointer> allGUIs = itk::ObjectFactoryBase::CreateAllInstance(guiClassname.c_str());
   for (auto iter = allGUIs.begin(); iter != allGUIs.end(); ++iter)
   {
     if (object.IsNull())
     {
       object = dynamic_cast<itk::Object *>(iter->GetPointer());
     }
     else
     {
       MITK_ERROR << "There is more than one GUI for " << classname << " (several factories claim ability to produce a "
                  << guiClassname << " ) " << std::endl;
       return nullptr; // people should see and fix this error
     }
   }
 
   return object;
 }
 
 mitk::NodePredicateBase::ConstPointer mitk::Tool::GetReferenceDataPreference() const
 {
   return m_PredicateReference.GetPointer();
 }
 
 mitk::NodePredicateBase::ConstPointer mitk::Tool::GetWorkingDataPreference() const
 {
   return m_IsSegmentationPredicate.GetPointer();
 }
 
 mitk::DataNode::Pointer mitk::Tool::CreateEmptySegmentationNode(const Image *original,
                                                                 const std::string &organName,
                                                                 const mitk::Color &color) const
 {
   // we NEED a reference image for size etc.
   if (!original)
     return nullptr;
 
   // actually create a new empty segmentation
   PixelType pixelType(mitk::MakeScalarPixelType<DefaultSegmentationDataType>());
   LabelSetImage::Pointer segmentation = LabelSetImage::New();
 
   if (original->GetDimension() == 2)
   {
     const unsigned int dimensions[] = {original->GetDimension(0), original->GetDimension(1), 1};
     segmentation->Initialize(pixelType, 3, dimensions);
     segmentation->AddLayer();
   }
   else
   {
     segmentation->Initialize(original);
   }
 
   mitk::Label::Pointer label = mitk::Label::New();
   label->SetName(organName);
   label->SetColor(color);
   label->SetValue(1);
-  segmentation->GetActiveLabelSet()->AddLabel(label);
-  segmentation->GetActiveLabelSet()->SetActiveLabel(1);
+  segmentation->AddLabel(label,segmentation->GetActiveLayer());
+  segmentation->SetActiveLabel(label->GetValue());
 
   unsigned int byteSize = sizeof(mitk::Label::PixelType);
 
   if (segmentation->GetDimension() < 4)
   {
     for (unsigned int dim = 0; dim < segmentation->GetDimension(); ++dim)
     {
       byteSize *= segmentation->GetDimension(dim);
     }
 
     mitk::ImageWriteAccessor writeAccess(segmentation.GetPointer(), segmentation->GetVolumeData(0));
 
     memset(writeAccess.GetData(), 0, byteSize);
   }
   else
   {
     // if we have a time-resolved image we need to set memory to 0 for each time step
     for (unsigned int dim = 0; dim < 3; ++dim)
     {
       byteSize *= segmentation->GetDimension(dim);
     }
 
     for (unsigned int volumeNumber = 0; volumeNumber < segmentation->GetDimension(3); volumeNumber++)
     {
       mitk::ImageWriteAccessor writeAccess(segmentation.GetPointer(), segmentation->GetVolumeData(volumeNumber));
 
       memset(writeAccess.GetData(), 0, byteSize);
     }
   }
 
   if (original->GetTimeGeometry())
   {
     TimeGeometry::Pointer originalGeometry = original->GetTimeGeometry()->Clone();
     segmentation->SetTimeGeometry(originalGeometry);
   }
   else
   {
     Tool::ErrorMessage("Original image does not have a 'Time sliced geometry'! Cannot create a segmentation.");
     return nullptr;
   }
 
   return CreateSegmentationNode(segmentation, organName, color);
 }
 
 mitk::DataNode::Pointer mitk::Tool::CreateSegmentationNode(Image *image,
                                                            const std::string &organName,
                                                            const mitk::Color &color) const
 {
   if (!image)
     return nullptr;
 
   // decorate the datatreenode with some properties
   DataNode::Pointer segmentationNode = DataNode::New();
   segmentationNode->SetData(image);
 
   // name
   segmentationNode->SetProperty("name", StringProperty::New(organName));
 
   // visualization properties
   segmentationNode->SetProperty("binary", BoolProperty::New(true));
   segmentationNode->SetProperty("color", ColorProperty::New(color));
   mitk::LookupTable::Pointer lut = mitk::LookupTable::New();
   lut->SetType(mitk::LookupTable::MULTILABEL);
   mitk::LookupTableProperty::Pointer lutProp = mitk::LookupTableProperty::New();
   lutProp->SetLookupTable(lut);
   segmentationNode->SetProperty("LookupTable", lutProp);
   segmentationNode->SetProperty("texture interpolation", BoolProperty::New(false));
   segmentationNode->SetProperty("layer", IntProperty::New(10));
   segmentationNode->SetProperty("levelwindow", LevelWindowProperty::New(LevelWindow(0.5, 1)));
   segmentationNode->SetProperty("opacity", FloatProperty::New(0.3));
   segmentationNode->SetProperty("segmentation", BoolProperty::New(true));
   segmentationNode->SetProperty("reslice interpolation",
                                 VtkResliceInterpolationProperty::New()); // otherwise -> segmentation appears in 2
                                                                          // slices sometimes (only visual effect, not
                                                                          // different data)
   // For MITK-3M3 release, the volume of all segmentations should be shown
   segmentationNode->SetProperty("showVolume", BoolProperty::New(true));
 
   return segmentationNode;
 }
 
 us::ModuleResource mitk::Tool::GetIconResource() const
 {
   // Each specific tool should load its own resource. This one will be invalid
   return us::ModuleResource();
 }
 
 us::ModuleResource mitk::Tool::GetCursorIconResource() const
 {
   // Each specific tool should load its own resource. This one will be invalid
   return us::ModuleResource();
 }
diff --git a/Modules/Segmentation/Interactions/mitkTotalSegmentatorTool.cpp b/Modules/Segmentation/Interactions/mitkTotalSegmentatorTool.cpp
index c3ac4dffd4..b65ed9fe8d 100644
--- a/Modules/Segmentation/Interactions/mitkTotalSegmentatorTool.cpp
+++ b/Modules/Segmentation/Interactions/mitkTotalSegmentatorTool.cpp
@@ -1,354 +1,347 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 // MITK
 #include "mitkTotalSegmentatorTool.h"
 
 #include <mitkIOUtil.h>
 #include <mitkImageReadAccessor.h>
 
 #include <algorithm>
 #include <filesystem>
 #include <itksys/SystemTools.hxx>
 #include <regex>
 
 // us
 #include <usGetModuleContext.h>
 #include <usModule.h>
 #include <usModuleContext.h>
 #include <usModuleResource.h>
 #include <usServiceReference.h>
 
 namespace mitk
 {
   MITK_TOOL_MACRO(MITKSEGMENTATION_EXPORT, TotalSegmentatorTool, "Total Segmentator");
 }
 
 mitk::TotalSegmentatorTool::~TotalSegmentatorTool()
 {
   std::filesystem::remove_all(this->GetMitkTempDir());
 }
 
 mitk::TotalSegmentatorTool::TotalSegmentatorTool() : SegWithPreviewTool(true) // prevents auto-compute across all timesteps
 {
   this->IsTimePointChangeAwareOff();
 }
 
 void mitk::TotalSegmentatorTool::Activated()
 {
   Superclass::Activated();
   this->SetLabelTransferScope(LabelTransferScope::AllLabels);
   this->SetLabelTransferMode(LabelTransferMode::AddLabel);
 }
 
 const char **mitk::TotalSegmentatorTool::GetXPM() const
 {
   return nullptr;
 }
 
 us::ModuleResource mitk::TotalSegmentatorTool::GetIconResource() const
 {
   us::Module *module = us::GetModuleContext()->GetModule();
   us::ModuleResource resource = module->GetResource("AI.svg");
   return resource;
 }
 
 const char *mitk::TotalSegmentatorTool::GetName() const
 {
   return "TotalSegmentator";
 }
 
 void mitk::TotalSegmentatorTool::onPythonProcessEvent(itk::Object * /*pCaller*/, const itk::EventObject &e, void *)
 {
   std::string testCOUT;
   std::string testCERR;
   const auto *pEvent = dynamic_cast<const mitk::ExternalProcessStdOutEvent *>(&e);
 
   if (pEvent)
   {
     testCOUT = testCOUT + pEvent->GetOutput();
     MITK_INFO << testCOUT;
   }
 
   const auto *pErrEvent = dynamic_cast<const mitk::ExternalProcessStdErrEvent *>(&e);
 
   if (pErrEvent)
   {
     testCERR = testCERR + pErrEvent->GetOutput();
     MITK_ERROR << testCERR;
   }
 }
 
 void mitk::TotalSegmentatorTool::DoUpdatePreview(const Image *inputAtTimeStep,
                                                  const Image * /*oldSegAtTimeStep*/,
                                                  LabelSetImage *previewImage,
                                                  TimeStepType timeStep)
 {
   if (this->m_MitkTempDir.empty())
   {
     this->SetMitkTempDir(IOUtil::CreateTemporaryDirectory("mitk-XXXXXX"));
   }
   ProcessExecutor::Pointer spExec = ProcessExecutor::New();
   itk::CStyleCommand::Pointer spCommand = itk::CStyleCommand::New();
   spCommand->SetCallback(&onPythonProcessEvent);
   spExec->AddObserver(ExternalProcessOutputEvent(), spCommand);
   m_ProgressCommand->SetProgress(5);
 
   std::string inDir, outDir, inputImagePath, outputImagePath, scriptPath;
   inDir = IOUtil::CreateTemporaryDirectory("totalseg-in-XXXXXX", this->GetMitkTempDir());
   std::ofstream tmpStream;
   inputImagePath = IOUtil::CreateTemporaryFile(tmpStream, TEMPLATE_FILENAME, inDir + IOUtil::GetDirectorySeparator());
   tmpStream.close();
   std::size_t found = inputImagePath.find_last_of(IOUtil::GetDirectorySeparator());
   std::string fileName = inputImagePath.substr(found + 1);
   std::string token = fileName.substr(0, fileName.find("_"));
   outDir = IOUtil::CreateTemporaryDirectory("totalseg-out-XXXXXX", this->GetMitkTempDir());
   LabelSetImage::Pointer outputBuffer;
   m_ProgressCommand->SetProgress(20);
   IOUtil::Save(inputAtTimeStep, inputImagePath);
   m_ProgressCommand->SetProgress(50);
 
   outputImagePath = outDir + IOUtil::GetDirectorySeparator() + token + "_000.nii.gz";
   const bool isSubTask = (this->GetSubTask() != DEFAULT_TOTAL_TASK);
   if (isSubTask)
   {
     outputImagePath = outDir;
     this->run_totalsegmentator(
       spExec, inputImagePath, outputImagePath, !isSubTask, !isSubTask, this->GetGpuId(), this->GetSubTask());
     // Construct Label Id map
     std::vector<std::string> files = SUBTASKS_MAP.at(this->GetSubTask());
     // Agglomerate individual mask files into one multi-label image.
     std::for_each(files.begin(),
                   files.end(),
                   [&](std::string &fileName) { fileName = (outDir + IOUtil::GetDirectorySeparator() + fileName); });
     outputBuffer = AgglomerateLabelFiles(files, inputAtTimeStep->GetDimensions(), inputAtTimeStep->GetGeometry());
   }
   else
   {
     this->run_totalsegmentator(
       spExec, inputImagePath, outputImagePath, this->GetFast(), !isSubTask, this->GetGpuId(), DEFAULT_TOTAL_TASK);
     Image::Pointer outputImage = IOUtil::Load<Image>(outputImagePath);
     outputBuffer = mitk::LabelSetImage::New();
     outputBuffer->InitializeByLabeledImage(outputImage);
     outputBuffer->SetGeometry(inputAtTimeStep->GetGeometry());
   }
   m_ProgressCommand->SetProgress(180);
   mitk::ImageReadAccessor newMitkImgAcc(outputBuffer.GetPointer());
   this->MapLabelsToSegmentation(outputBuffer, previewImage, m_LabelMapTotal);
   previewImage->SetVolume(newMitkImgAcc.GetData(), timeStep);
 }
 
 void mitk::TotalSegmentatorTool::UpdatePrepare()
 {
   Superclass::UpdatePrepare();
   auto preview = this->GetPreviewSegmentation();
-  for (LabelSetImage::GroupIndexType i = 0; i < preview->GetNumberOfLayers(); ++i)
-  {
-    preview->GetLabelSet(i)->RemoveAllLabels();
-  }
+  preview->RemoveLabels(preview->GetAllLabelValues());
   if (m_LabelMapTotal.empty())
   {
     this->ParseLabelMapTotalDefault();
   }
   const bool isSubTask = (this->GetSubTask() != DEFAULT_TOTAL_TASK);
   if (isSubTask)
   {
     std::vector<std::string> files = SUBTASKS_MAP.at(this->GetSubTask());
     m_LabelMapTotal.clear();
     mitk::Label::PixelType labelId = 1;
     for (auto const &file : files)
     {
       std::string labelName = file.substr(0, file.find('.'));
       m_LabelMapTotal[labelId] = labelName;
       labelId++;
     }
   }
 }
 
 mitk::LabelSetImage::Pointer mitk::TotalSegmentatorTool::AgglomerateLabelFiles(std::vector<std::string> &filePaths,
                                                                                const unsigned int *dimensions,
                                                                                mitk::BaseGeometry *geometry)
 {
   Label::PixelType labelId = 1;
   auto aggloLabelImage = mitk::LabelSetImage::New();
   auto initImage = mitk::Image::New();
   initImage->Initialize(mitk::MakeScalarPixelType<mitk::Label::PixelType>(), 3, dimensions);
   aggloLabelImage->Initialize(initImage);
   aggloLabelImage->SetGeometry(geometry);
-  mitk::LabelSet::Pointer newlayer = mitk::LabelSet::New();
-  newlayer->SetLayer(0);
-  aggloLabelImage->AddLayer(newlayer);
+  const auto layerIndex = aggloLabelImage->AddLayer();
 
   for (auto const &outputImagePath : filePaths)
   {
     double rgba[4];
-    aggloLabelImage->GetActiveLabelSet()->GetLookupTable()->GetTableValue(labelId, rgba);
+    aggloLabelImage->GetLookupTable()->GetTableValue(labelId, rgba);
     mitk::Color color;
     color.SetRed(rgba[0]);
     color.SetGreen(rgba[1]);
     color.SetBlue(rgba[2]);
 
     auto label = mitk::Label::New();
     label->SetName("object-" + std::to_string(labelId));
     label->SetValue(labelId);
     label->SetColor(color);
     label->SetOpacity(rgba[3]);
 
-    aggloLabelImage->GetActiveLabelSet()->AddLabel(label);
+    aggloLabelImage->AddLabel(label, layerIndex, false, false);
 
     Image::Pointer outputImage = IOUtil::Load<Image>(outputImagePath);
     auto source = mitk::LabelSetImage::New();
     source->InitializeByLabeledImage(outputImage);
     source->SetGeometry(geometry);
 
-    auto labelSet = aggloLabelImage->GetActiveLabelSet();
-    mitk::TransferLabelContent(source, aggloLabelImage, labelSet, 0, 0, false, {{1, labelId}});
+    mitk::TransferLabelContent(source, aggloLabelImage, aggloLabelImage->GetConstLabelsByValue(aggloLabelImage->GetLabelValuesByGroup(layerIndex)), 0, 0, false, {{1, labelId}});
     labelId++;
   }
   return aggloLabelImage;
 }
 
 void mitk::TotalSegmentatorTool::run_totalsegmentator(ProcessExecutor* spExec,
                                                       const std::string &inputImagePath,
                                                       const std::string &outputImagePath,
                                                       bool isFast,
                                                       bool isMultiLabel,
                                                       unsigned int gpuId,
                                                       const std::string &subTask)
 {
   ProcessExecutor::ArgumentListType args;
   std::string command = "TotalSegmentator";
 #ifdef _WIN32
   command += ".exe";
 #endif
   args.clear();
   args.push_back("-i");
   args.push_back(inputImagePath);
 
   args.push_back("-o");
   args.push_back(outputImagePath);
 
   if (subTask != DEFAULT_TOTAL_TASK)
   {
     args.push_back("-ta");
     args.push_back(subTask);
   }
 
   if (isMultiLabel)
   {
     args.push_back("--ml");
   }
 
   if (isFast)
   {
     args.push_back("--fast");
   }
 
   try
   {
     std::string cudaEnv = "CUDA_VISIBLE_DEVICES=" + std::to_string(gpuId);
     itksys::SystemTools::PutEnv(cudaEnv.c_str());
     
     std::stringstream logStream;
     for (const auto &arg : args)
       logStream << arg << " ";
     logStream << this->GetPythonPath();
     MITK_INFO << logStream.str();
 
     spExec->Execute(this->GetPythonPath(), command, args);
   }
   catch (const mitk::Exception &e)
   {
     MITK_ERROR << e.GetDescription();
     return;
   }
 }
 
 void mitk::TotalSegmentatorTool::ParseLabelMapTotalDefault()
 {
   if (!this->GetLabelMapPath().empty())
   {
     std::regex sanitizer(R"([^A-Za-z0-9_])");
     std::fstream newfile;
     newfile.open(this->GetLabelMapPath(), ios::in);
     std::stringstream buffer;
     if (newfile.is_open())
     {
       int line = 0;
       std::string temp;
       while (std::getline(newfile, temp))
       {
         if (line > 111 && line < 229)
         {
           buffer << temp;
         }
         ++line;
       }
     }
     std::string key, val;
     while (std::getline(std::getline(buffer, key, ':'), val, ','))
     {
       std::string sanitized = std::regex_replace(val, sanitizer, "");
       m_LabelMapTotal[std::stoi(key)] = sanitized;
     }
   }
 }
 
 void mitk::TotalSegmentatorTool::MapLabelsToSegmentation(const mitk::LabelSetImage* source,
                                                          mitk::LabelSetImage* dest,
                                                          std::map<mitk::Label::PixelType, std::string> &labelMap)
 {
-  auto labelset = dest->GetLabelSet();
   auto lookupTable = mitk::LookupTable::New();
   lookupTable->SetType(mitk::LookupTable::LookupTableType::MULTILABEL);
   for (auto const &[key, val] : labelMap)
   {
     if (source->ExistLabel(key, source->GetActiveLayer()))
     {
       Label::Pointer label = Label::New(key, val);
       std::array<double, 3> lookupTableColor;
       lookupTable->GetColor(key, lookupTableColor.data());
       Color color;
       color.SetRed(lookupTableColor[0]);
       color.SetGreen(lookupTableColor[1]);
       color.SetBlue(lookupTableColor[2]);
       label->SetColor(color);
-      labelset->AddLabel(label, false);
+      dest->AddLabel(label, 0,false);
     }
   }
 }
 
 std::string mitk::TotalSegmentatorTool::GetLabelMapPath()
 {
   std::string pythonFileName;
   std::filesystem::path pathToLabelMap(this->GetPythonPath());
   pathToLabelMap = pathToLabelMap.parent_path();
 #ifdef _WIN32
   pythonFileName = pathToLabelMap.string() + "/Lib/site-packages/totalsegmentator/map_to_binary.py";
 #else
   pathToLabelMap.append("lib");
   for (auto const &dir_entry : std::filesystem::directory_iterator{pathToLabelMap})
   {
     if (dir_entry.is_directory())
     {
       auto dirName = dir_entry.path().filename().string();
       if (dirName.rfind("python", 0) == 0)
       {
         pathToLabelMap.append(dir_entry.path().filename().string());
         break;
       }
     }
   }
   pythonFileName = pathToLabelMap.string() + "/site-packages/totalsegmentator/map_to_binary.py";
 #endif
   return pythonFileName;
 }
diff --git a/Modules/Segmentation/Interactions/mitknnUnetTool.cpp b/Modules/Segmentation/Interactions/mitknnUnetTool.cpp
index d2e923b8e0..6af435b28e 100644
--- a/Modules/Segmentation/Interactions/mitknnUnetTool.cpp
+++ b/Modules/Segmentation/Interactions/mitknnUnetTool.cpp
@@ -1,323 +1,322 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "mitknnUnetTool.h"
 
 #include "mitkIOUtil.h"
 #include "mitkProcessExecutor.h"
 #include <itksys/SystemTools.hxx>
 #include <usGetModuleContext.h>
 #include <usModule.h>
 #include <usModuleContext.h>
 #include <usModuleResource.h>
 #include <filesystem>
 
 namespace mitk
 {
   MITK_TOOL_MACRO(MITKSEGMENTATION_EXPORT, nnUNetTool, "nnUNet tool");
 }
 
 mitk::nnUNetTool::~nnUNetTool()
 {
   std::filesystem::remove_all(this->GetMitkTempDir());
 }
 
 void mitk::nnUNetTool::Activated()
 {
   Superclass::Activated();
   this->SetLabelTransferScope(LabelTransferScope::AllLabels);
   this->SetLabelTransferMode(LabelTransferMode::AddLabel);
 }
 
 void mitk::nnUNetTool::RenderOutputBuffer()
 {
   if (m_OutputBuffer != nullptr)
   {
     try
     {
       if (nullptr != this->GetPreviewSegmentationNode())
       {
         auto previewImage = this->GetPreviewSegmentation();
         previewImage->InitializeByLabeledImage(m_OutputBuffer);
       }
     }
     catch (const mitk::Exception &e)
     {
       MITK_INFO << e.GetDescription();
     }
   }
 }
 
 void mitk::nnUNetTool::SetOutputBuffer(LabelSetImage::Pointer segmentation)
 {
   m_OutputBuffer = segmentation;
 }
 
 mitk::LabelSetImage::Pointer mitk::nnUNetTool::GetOutputBuffer()
 {
   return m_OutputBuffer;
 }
 
 void mitk::nnUNetTool::ClearOutputBuffer()
 {
   m_OutputBuffer = nullptr;
 }
 
 us::ModuleResource mitk::nnUNetTool::GetIconResource() const
 {
   us::Module *module = us::GetModuleContext()->GetModule();
   us::ModuleResource resource = module->GetResource("AI.svg");
   return resource;
 }
 
 const char **mitk::nnUNetTool::GetXPM() const
 {
   return nullptr;
 }
 
 const char *mitk::nnUNetTool::GetName() const
 {
   return "nnUNet";
 }
 
 mitk::DataStorage *mitk::nnUNetTool::GetDataStorage()
 {
   return this->GetToolManager()->GetDataStorage();
 }
 
 mitk::DataNode *mitk::nnUNetTool::GetRefNode()
 {
   return this->GetToolManager()->GetReferenceData(0);
 }
 
 void mitk::nnUNetTool::UpdatePrepare()
 {
   Superclass::UpdatePrepare();
   auto preview = this->GetPreviewSegmentation();
-  auto labelset = preview->GetLabelSet(preview->GetActiveLayer());
-  labelset->RemoveAllLabels();
+  preview->RemoveLabels(preview->GetLabelValuesByGroup(preview->GetActiveLayer()));
 }
 
 namespace
 {
   void onPythonProcessEvent(itk::Object * /*pCaller*/, const itk::EventObject &e, void *)
   {
     std::string testCOUT;
     std::string testCERR;
     const auto *pEvent = dynamic_cast<const mitk::ExternalProcessStdOutEvent *>(&e);
 
     if (pEvent)
     {
       testCOUT = testCOUT + pEvent->GetOutput();
       MITK_INFO << testCOUT;
     }
 
     const auto *pErrEvent = dynamic_cast<const mitk::ExternalProcessStdErrEvent *>(&e);
 
     if (pErrEvent)
     {
       testCERR = testCERR + pErrEvent->GetOutput();
       MITK_ERROR << testCERR;
     }
   }
 } // namespace
 
 void mitk::nnUNetTool::DoUpdatePreview(const Image* inputAtTimeStep, const Image* /*oldSegAtTimeStep*/, LabelSetImage* previewImage, TimeStepType /*timeStep*/)
 {
   if (this->GetMitkTempDir().empty())
   {
     this->SetMitkTempDir(IOUtil::CreateTemporaryDirectory("mitk-nnunet-XXXXXX"));
   }
   std::string inDir, outDir, inputImagePath, outputImagePath, scriptPath;
 
   ProcessExecutor::Pointer spExec = ProcessExecutor::New();
   itk::CStyleCommand::Pointer spCommand = itk::CStyleCommand::New();
   spCommand->SetCallback(&onPythonProcessEvent);
   spExec->AddObserver(ExternalProcessOutputEvent(), spCommand);
   ProcessExecutor::ArgumentListType args;
 
   inDir = IOUtil::CreateTemporaryDirectory("nnunet-in-XXXXXX", this->GetMitkTempDir());
   std::ofstream tmpStream;
   inputImagePath = IOUtil::CreateTemporaryFile(tmpStream, m_TEMPLATE_FILENAME, inDir + IOUtil::GetDirectorySeparator());
   tmpStream.close();
   std::size_t found = inputImagePath.find_last_of(IOUtil::GetDirectorySeparator());
   std::string fileName = inputImagePath.substr(found + 1);
   std::string token = fileName.substr(0, fileName.find("_"));
 
   if (this->GetNoPip())
   {
     scriptPath = this->GetnnUNetDirectory() + IOUtil::GetDirectorySeparator() + "nnunet" +
                  IOUtil::GetDirectorySeparator() + "inference" + IOUtil::GetDirectorySeparator() + "predict_simple.py";
   }
 
   try
   {
     if (this->GetMultiModal())
     {
       const std::string fileFormat(".nii.gz");
       const std::string fileNamePart("_000_000");
       std::string outModalFile;
       size_t len = inDir.length() + 1 + token.length() + fileNamePart.length() + 1 + fileFormat.length();
       outModalFile.reserve(len); // The 1(s) indicates a directory separator char and an underscore.
       for (size_t i = 0; i < m_OtherModalPaths.size(); ++i)
       {
         mitk::Image::ConstPointer modalImage = m_OtherModalPaths[i];
         outModalFile.append(inDir);
         outModalFile.push_back(IOUtil::GetDirectorySeparator());
         outModalFile.append(token);
         outModalFile.append(fileNamePart);
         outModalFile.append(std::to_string(i));
         outModalFile.append(fileFormat);
         IOUtil::Save(modalImage.GetPointer(), outModalFile);
         outModalFile.clear();
       }
     }
     else
     {
       IOUtil::Save(inputAtTimeStep, inputImagePath);
     }
   }
   catch (const mitk::Exception &e)
   {
     MITK_ERROR << e.GetDescription();
     return;
   }
   // Code calls external process
   std::string command = "nnUNet_predict";
   if (this->GetNoPip())
   {
 #ifdef _WIN32
     command = "python";
 #else
     command = "python3";
 #endif
   }
   for (ModelParams &modelparam : m_ParamQ)
   {
     outDir = IOUtil::CreateTemporaryDirectory("nnunet-out-XXXXXX", this->GetMitkTempDir());
     outputImagePath = outDir + IOUtil::GetDirectorySeparator() + token + "_000.nii.gz";
     modelparam.outputDir = outDir;
     args.clear();
     if (this->GetNoPip())
     {
       args.push_back(scriptPath);
     }
     args.push_back("-i");
     args.push_back(inDir);
 
     args.push_back("-o");
     args.push_back(outDir);
 
     args.push_back("-t");
     args.push_back(modelparam.task);
 
     if (modelparam.model.find("cascade") != std::string::npos)
     {
       args.push_back("-ctr");
     }
     else
     {
       args.push_back("-tr");
     }
     args.push_back(modelparam.trainer);
 
     args.push_back("-m");
     args.push_back(modelparam.model);
 
     args.push_back("-p");
     args.push_back(modelparam.planId);
 
     if (!modelparam.folds.empty())
     {
       args.push_back("-f");
       for (auto fold : modelparam.folds)
       {
         args.push_back(fold);
       }
     }
 
     args.push_back("--num_threads_nifti_save");
     args.push_back("1"); // fixing to 1
 
     if (!this->GetMirror())
     {
       args.push_back("--disable_tta");
     }
 
     if (!this->GetMixedPrecision())
     {
       args.push_back("--disable_mixed_precision");
     }
 
     if (this->GetEnsemble())
     {
       args.push_back("--save_npz");
     }
 
     try
     {
       std::string resultsFolderEnv = "RESULTS_FOLDER=" + this->GetModelDirectory();
       itksys::SystemTools::PutEnv(resultsFolderEnv.c_str());
       std::string cudaEnv = "CUDA_VISIBLE_DEVICES=" + std::to_string(this->GetGpuId());
       itksys::SystemTools::PutEnv(cudaEnv.c_str());
 
       spExec->Execute(this->GetPythonPath(), command, args);
     }
     catch (const mitk::Exception &e)
     {
       /*
       Can't throw mitk exception to the caller. Refer: T28691
       */
       MITK_ERROR << e.GetDescription();
       return;
     }
   }
   if (this->GetEnsemble() && !this->GetPostProcessingJsonDirectory().empty())
   {
     args.clear();
     command = "nnUNet_ensemble";
     outDir = IOUtil::CreateTemporaryDirectory("nnunet-ensemble-out-XXXXXX", this->GetMitkTempDir());
     outputImagePath = outDir + IOUtil::GetDirectorySeparator() + token + "_000.nii.gz";
 
     args.push_back("-f");
     for (ModelParams &modelparam : m_ParamQ)
     {
       args.push_back(modelparam.outputDir);
     }
 
     args.push_back("-o");
     args.push_back(outDir);
 
     if (!this->GetPostProcessingJsonDirectory().empty())
     {
       args.push_back("-pp");
       args.push_back(this->GetPostProcessingJsonDirectory());
     }
 
     spExec->Execute(this->GetPythonPath(), command, args);
   }
   try
   {
     Image::Pointer outputImage = IOUtil::Load<Image>(outputImagePath);
     previewImage->InitializeByLabeledImage(outputImage);
     previewImage->SetGeometry(inputAtTimeStep->GetGeometry());
     m_InputBuffer = inputAtTimeStep;
     m_OutputBuffer = mitk::LabelSetImage::New();
     m_OutputBuffer->InitializeByLabeledImage(outputImage);
     m_OutputBuffer->SetGeometry(inputAtTimeStep->GetGeometry());
   }
   catch (const mitk::Exception &e)
   {
     MITK_ERROR << e.GetDescription();
     return;
   }
 }