diff --git a/Modules/ContourModel/Algorithms/mitkContourModelUtils.cpp b/Modules/ContourModel/Algorithms/mitkContourModelUtils.cpp
index e53d577736..6ba5a6e95a 100755
--- a/Modules/ContourModel/Algorithms/mitkContourModelUtils.cpp
+++ b/Modules/ContourModel/Algorithms/mitkContourModelUtils.cpp
@@ -1,292 +1,292 @@
 /*============================================================================
 
 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 <mitkContourModelUtils.h>
 
 #include <mitkContourModelToSurfaceFilter.h>
 #include <mitkLabelSetImage.h>
 #include <mitkSurface.h>
 #include <vtkImageStencil.h>
 #include <vtkPointData.h>
 #include <vtkPolyData.h>
 #include <vtkPolyDataToImageStencil.h>
 
 mitk::ContourModelUtils::ContourModelUtils()
 {
 }
 
 mitk::ContourModelUtils::~ContourModelUtils()
 {
 }
 
 mitk::ContourModel::Pointer mitk::ContourModelUtils::ProjectContourTo2DSlice(
   const Image *slice, const ContourModel *contourIn3D)
 {
   if (nullptr == slice || nullptr == contourIn3D)
     return nullptr;
 
   auto projectedContour = ContourModel::New();
   projectedContour->Initialize(*contourIn3D);
 
   auto sliceGeometry = slice->GetGeometry();
   const auto numberOfTimesteps = static_cast<TimeStepType>(contourIn3D->GetTimeSteps());
 
   for (std::remove_const_t<decltype(numberOfTimesteps)> t = 0; t < numberOfTimesteps; ++t)
   {
     auto iter = contourIn3D->Begin(t);
     auto end = contourIn3D->End(t);
 
     while (iter != end)
     {
       const auto &currentPointIn3D = (*iter)->Coordinates;
 
       Point3D projectedPointIn2D;
       projectedPointIn2D.Fill(0.0);
 
       sliceGeometry->WorldToIndex(currentPointIn3D, projectedPointIn2D);
 
       projectedContour->AddVertex(projectedPointIn2D, t);
       ++iter;
     }
   }
 
   return projectedContour;
 }
 
 mitk::ContourModel::Pointer mitk::ContourModelUtils::BackProjectContourFrom2DSlice(
   const BaseGeometry *sliceGeometry, const ContourModel *contourIn2D)
 {
   if (nullptr == sliceGeometry || nullptr == contourIn2D)
     return nullptr;
 
   auto worldContour = ContourModel::New();
   worldContour->Initialize(*contourIn2D);
 
   const auto numberOfTimesteps = static_cast<TimeStepType>(contourIn2D->GetTimeSteps());
 
   for (std::remove_const_t<decltype(numberOfTimesteps)> t = 0; t < numberOfTimesteps; ++t)
   {
     auto iter = contourIn2D->Begin(t);
     auto end = contourIn2D->End(t);
 
     while (iter != end)
     {
       const auto &currentPointIn2D = (*iter)->Coordinates;
 
       Point3D worldPointIn3D;
       worldPointIn3D.Fill(0.0);
 
       sliceGeometry->IndexToWorld(currentPointIn2D, worldPointIn3D);
 
       worldContour->AddVertex(worldPointIn3D, t);
       ++iter;
     }
   }
 
   return worldContour;
 }
 
 void mitk::ContourModelUtils::FillContourInSlice2(
   const ContourModel* projectedContour, Image* sliceImage, int paintingPixelValue)
 {
   FillContourInSlice2(projectedContour, 0, sliceImage, paintingPixelValue);
 }
 
 void mitk::ContourModelUtils::FillContourInSlice2(
   const ContourModel* projectedContour, TimeStepType contourTimeStep, Image* sliceImage, int paintingPixelValue)
 {
   if (nullptr == projectedContour)
   {
     mitkThrow() << "Cannot fill contour in slice. Passed contour is invalid";
   }
 
   if (nullptr == sliceImage)
   {
     mitkThrow() << "Cannot fill contour in slice. Passed slice is invalid";
   }
 
   auto contourModelFilter = mitk::ContourModelToSurfaceFilter::New();
   contourModelFilter->SetInput(projectedContour);
   contourModelFilter->Update();
 
   auto surface = mitk::Surface::New();
   surface = contourModelFilter->GetOutput();
 
   if (nullptr == surface->GetVtkPolyData(contourTimeStep))
   {
     MITK_WARN << "Could not create surface from contour model.";
     return;
   }
 
   auto surface2D = vtkSmartPointer<vtkPolyData>::New();
   surface2D->SetPoints(surface->GetVtkPolyData(contourTimeStep)->GetPoints());
   surface2D->SetLines(surface->GetVtkPolyData(contourTimeStep)->GetLines());
 
   auto polyDataToImageStencil = vtkSmartPointer<vtkPolyDataToImageStencil>::New();
 
   // Set a minimal tolerance, so that clipped pixels will be added to contour as well.
   polyDataToImageStencil->SetTolerance(mitk::eps);
   polyDataToImageStencil->SetInputData(surface2D);
   polyDataToImageStencil->Update();
 
   auto imageStencil = vtkSmartPointer<vtkImageStencil>::New();
 
   imageStencil->SetInputData(sliceImage->GetVtkImageData());
   imageStencil->SetStencilConnection(polyDataToImageStencil->GetOutputPort());
   imageStencil->ReverseStencilOn();
   imageStencil->SetBackgroundValue(paintingPixelValue);
   imageStencil->Update();
 
   vtkSmartPointer<vtkImageData> filledImage = imageStencil->GetOutput();
 
   sliceImage->SetVolume(filledImage->GetScalarPointer());
 }
 
 void mitk::ContourModelUtils::FillContourInSlice(
   const ContourModel *projectedContour, Image *sliceImage, const Image* workingImage, int paintingPixelValue)
 {
   FillContourInSlice(projectedContour, 0, sliceImage, workingImage, paintingPixelValue);
 }
 
 void mitk::ContourModelUtils::FillContourInSlice(
   const ContourModel *projectedContour, TimeStepType contourTimeStep, Image *sliceImage, const Image* workingImage, int paintingPixelValue)
 {
   if (nullptr == projectedContour)
   {
     mitkThrow() << "Cannot fill contour in slice. Passed contour is invalid";
   }
 
   if (nullptr == sliceImage)
   {
     mitkThrow() << "Cannot fill contour in slice. Passed slice is invalid";
   }
 
   auto contourModelFilter = mitk::ContourModelToSurfaceFilter::New();
   contourModelFilter->SetInput(projectedContour);
   contourModelFilter->Update();
 
   auto surface = mitk::Surface::New();
   surface = contourModelFilter->GetOutput();
 
   if (nullptr == surface->GetVtkPolyData(contourTimeStep))
   {
     MITK_WARN << "Could not create surface from contour model.";
     return;
   }
 
   auto surface2D = vtkSmartPointer<vtkPolyData>::New();
   surface2D->SetPoints(surface->GetVtkPolyData(contourTimeStep)->GetPoints());
   surface2D->SetLines(surface->GetVtkPolyData(contourTimeStep)->GetLines());
 
   auto image = vtkSmartPointer<vtkImageData>::New();
   image->DeepCopy(sliceImage->GetVtkImageData());
 
   const double FOREGROUND_VALUE = 255.0;
   const double BACKGROUND_VALUE = 0.0;
 
   const vtkIdType count = image->GetNumberOfPoints();
   for (std::remove_const_t<decltype(count)> i = 0; i < count; ++i)
     image->GetPointData()->GetScalars()->SetTuple1(i, FOREGROUND_VALUE);
 
   auto polyDataToImageStencil = vtkSmartPointer<vtkPolyDataToImageStencil>::New();
 
   // Set a minimal tolerance, so that clipped pixels will be added to contour as well.
   polyDataToImageStencil->SetTolerance(mitk::eps);
   polyDataToImageStencil->SetInputData(surface2D);
   polyDataToImageStencil->Update();
 
   auto imageStencil = vtkSmartPointer<vtkImageStencil>::New();
 
   imageStencil->SetInputData(image);
   imageStencil->SetStencilConnection(polyDataToImageStencil->GetOutputPort());
   imageStencil->ReverseStencilOff();
   imageStencil->SetBackgroundValue(BACKGROUND_VALUE);
   imageStencil->Update();
 
   vtkSmartPointer<vtkImageData> filledImage = imageStencil->GetOutput();
   vtkSmartPointer<vtkImageData> resultImage = sliceImage->GetVtkImageData();
   FillSliceInSlice(filledImage, resultImage, workingImage, paintingPixelValue);
 
   sliceImage->SetVolume(resultImage->GetScalarPointer());
 }
 
 void mitk::ContourModelUtils::FillSliceInSlice(
   vtkSmartPointer<vtkImageData> filledImage, vtkSmartPointer<vtkImageData> resultImage, const Image* image, int paintingPixelValue, double fillForegroundThreshold)
 {
   auto labelImage = dynamic_cast<const LabelSetImage *>(image);
   const auto numberOfPoints = filledImage->GetNumberOfPoints();
 
   if (nullptr == labelImage)
   {
     for (std::remove_const_t<decltype(numberOfPoints)> i = 0; i < numberOfPoints; ++i)
     {
       if (fillForegroundThreshold <= filledImage->GetPointData()->GetScalars()->GetTuple1(i))
         resultImage->GetPointData()->GetScalars()->SetTuple1(i, paintingPixelValue);
     }
   }
   else
   {
     if (paintingPixelValue != LabelSetImage::UnlabeledValue)
     {
       for (std::remove_const_t<decltype(numberOfPoints)> i = 0; i < numberOfPoints; ++i)
       {
         const auto filledValue = filledImage->GetPointData()->GetScalars()->GetTuple1(i);
         if (fillForegroundThreshold <= filledValue)
         {
           const auto existingValue = resultImage->GetPointData()->GetScalars()->GetTuple1(i);
 
           if (!labelImage->IsLabelLocked(existingValue))
             resultImage->GetPointData()->GetScalars()->SetTuple1(i, paintingPixelValue);
         }
       }
     }
     else
     {
-      const auto activePixelValue = labelImage->GetActiveLabel(labelImage->GetActiveLayer())->GetValue();
+      const auto activePixelValue = labelImage->GetActiveLabel()->GetValue();
       for (std::remove_const_t<decltype(numberOfPoints)> i = 0; i < numberOfPoints; ++i)
       {
         if (fillForegroundThreshold <= filledImage->GetPointData()->GetScalars()->GetTuple1(i))
         {
           if (resultImage->GetPointData()->GetScalars()->GetTuple1(i) == activePixelValue)
             resultImage->GetPointData()->GetScalars()->SetTuple1(i, paintingPixelValue);
         }
       }
     }
   }
 }
 
 mitk::ContourModel::Pointer mitk::ContourModelUtils::MoveZerothContourTimeStep(const ContourModel *contour, TimeStepType t)
 {
   if (nullptr == contour)
     return nullptr;
 
   auto resultContour = ContourModel::New();
   resultContour->Expand(t + 1);
 
   std::for_each(contour->Begin(), contour->End(), [&resultContour, t](ContourElement::VertexType *vertex) {
     resultContour->AddVertex(*vertex, t);
   });
 
   return resultContour;
 }
 
 int mitk::ContourModelUtils::GetActivePixelValue(const Image* workingImage)
 {
   auto labelSetImage = dynamic_cast<const LabelSetImage*>(workingImage);
   int activePixelValue = 1;
   if (nullptr != labelSetImage)
   {
-    activePixelValue = labelSetImage->GetActiveLabel(labelSetImage->GetActiveLayer())->GetValue();
+    activePixelValue = labelSetImage->GetActiveLabel()->GetValue();
   }
 
   return activePixelValue;
 }
diff --git a/Modules/MatchPointRegistration/src/Helper/mitkImageMappingHelper.cpp b/Modules/MatchPointRegistration/src/Helper/mitkImageMappingHelper.cpp
index 39a9e5f197..ba04efcada 100644
--- a/Modules/MatchPointRegistration/src/Helper/mitkImageMappingHelper.cpp
+++ b/Modules/MatchPointRegistration/src/Helper/mitkImageMappingHelper.cpp
@@ -1,482 +1,482 @@
 /*============================================================================
 
 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 <itkInterpolateImageFunction.h>
 #include <itkNearestNeighborInterpolateImageFunction.h>
 #include <itkLinearInterpolateImageFunction.h>
 #include <itkBSplineInterpolateImageFunction.h>
 #include <itkWindowedSincInterpolateImageFunction.h>
 
 #include <mitkImageAccessByItk.h>
 #include <mitkImageCast.h>
 #include <mitkGeometry3D.h>
 #include <mitkImageToItk.h>
 #include <mitkImageTimeSelector.h>
 #include <mitkLabelSetImage.h>
 
 #include "mapRegistration.h"
 
 #include "mitkImageMappingHelper.h"
 #include "mitkRegistrationHelper.h"
 
 template <typename TImage >
 typename ::itk::InterpolateImageFunction< TImage >::Pointer generateInterpolator(mitk::ImageMappingInterpolator::Type interpolatorType)
 {
   typedef ::itk::InterpolateImageFunction< TImage > BaseInterpolatorType;
   typename BaseInterpolatorType::Pointer result;
 
   switch (interpolatorType)
   {
   case mitk::ImageMappingInterpolator::NearestNeighbor:
     {
       result = ::itk::NearestNeighborInterpolateImageFunction<TImage>::New();
       break;
     }
   case mitk::ImageMappingInterpolator::BSpline_3:
     {
       typename ::itk::BSplineInterpolateImageFunction<TImage>::Pointer spInterpolator = ::itk::BSplineInterpolateImageFunction<TImage>::New();
       spInterpolator->SetSplineOrder(3);
       result = spInterpolator;
       break;
     }
   case mitk::ImageMappingInterpolator::WSinc_Hamming:
     {
       result = ::itk::WindowedSincInterpolateImageFunction<TImage,4>::New();
       break;
     }
   case mitk::ImageMappingInterpolator::WSinc_Welch:
     {
       result = ::itk::WindowedSincInterpolateImageFunction<TImage,4,::itk::Function::WelchWindowFunction<4> >::New();
       break;
     }
   default:
     {
       result = ::itk::LinearInterpolateImageFunction<TImage>::New();
       break;
     }
 
   }
 
   return result;
 };
 
 template <typename TPixelType, unsigned int VImageDimension >
 void doMITKMap(const ::itk::Image<TPixelType,VImageDimension>* input, mitk::ImageMappingHelper::ResultImageType::Pointer& result, const mitk::ImageMappingHelper::RegistrationType*& registration,
   bool throwOnOutOfInputAreaError, const double& paddingValue, const mitk::ImageMappingHelper::ResultImageGeometryType*& resultGeometry,
   bool throwOnMappingError, const double& errorValue, mitk::ImageMappingInterpolator::Type interpolatorType)
 {
   typedef ::map::core::Registration<VImageDimension,VImageDimension> ConcreteRegistrationType;
   typedef ::map::core::ImageMappingTask<ConcreteRegistrationType, ::itk::Image<TPixelType,VImageDimension>, ::itk::Image<TPixelType,VImageDimension> > MappingTaskType;
   typename MappingTaskType::Pointer spTask = MappingTaskType::New();
 
   typedef typename MappingTaskType::ResultImageDescriptorType ResultImageDescriptorType;
   typename ResultImageDescriptorType::Pointer resultDescriptor;
 
   //check if image and result geometry fits the passed registration
   /////////////////////////////////////////////////////////////////
   if (registration->getMovingDimensions()!=VImageDimension)
   {
     map::core::OStringStream str;
     str << "Dimension of MITK image ("<<VImageDimension<<") does not equal the moving dimension of the registration object ("<<registration->getMovingDimensions()<<").";
     throw mitk::AccessByItkException(str.str());
   }
 
   if (registration->getTargetDimensions()!=VImageDimension)
   {
     map::core::OStringStream str;
     str << "Dimension of MITK image ("<<VImageDimension<<") does not equal the target dimension of the registration object ("<<registration->getTargetDimensions()<<").";
     throw mitk::AccessByItkException(str.str());
   }
 
   const ConcreteRegistrationType* castedReg = dynamic_cast<const ConcreteRegistrationType*>(registration);
 
   if (registration->getTargetDimensions()==2 && resultGeometry)
   {
     mitk::ImageMappingHelper::ResultImageGeometryType::BoundsArrayType bounds = resultGeometry->GetBounds();
 
     if (bounds[4]!=0 || bounds[5]!=0)
     {
       //array "bounds" is constructed as [min Dim1, max Dim1, min Dim2, max Dim2, min Dim3, max Dim3]
       //therfore [4] and [5] must be 0
 
       map::core::OStringStream str;
       str << "Dimension of defined result geometry does not equal the target dimension of the registration object ("<<registration->getTargetDimensions()<<").";
       throw mitk::AccessByItkException(str.str());
     }
   }
 
   //check/create resultDescriptor
   /////////////////////////
   if (resultGeometry)
   {
     resultDescriptor = ResultImageDescriptorType::New();
 
     typename ResultImageDescriptorType::PointType origin;
     typename ResultImageDescriptorType::SizeType size;
     typename ResultImageDescriptorType::SpacingType fieldSpacing;
     typename ResultImageDescriptorType::DirectionType matrix;
 
     mitk::ImageMappingHelper::ResultImageGeometryType::BoundsArrayType geoBounds = resultGeometry->GetBounds();
     mitk::Vector3D geoSpacing = resultGeometry->GetSpacing();
     mitk::Point3D geoOrigin = resultGeometry->GetOrigin();
     mitk::AffineTransform3D::MatrixType geoMatrix = resultGeometry->GetIndexToWorldTransform()->GetMatrix();
 
     for (unsigned int i = 0; i<VImageDimension; ++i)
     {
       origin[i] = static_cast<typename ResultImageDescriptorType::PointType::ValueType>(geoOrigin[i]);
       fieldSpacing[i] = static_cast<typename ResultImageDescriptorType::SpacingType::ValueType>(geoSpacing[i]);
       size[i] = static_cast<typename ResultImageDescriptorType::SizeType::SizeValueType>(geoBounds[(2*i)+1]-geoBounds[2*i])*fieldSpacing[i];
     }
 
     //Matrix extraction
     matrix.SetIdentity();
     unsigned int i;
     unsigned int j;
 
     /// \warning 2D MITK images could have a 3D rotation, since they have a 3x3 geometry matrix.
     /// If it is only a rotation around the transversal plane normal, it can be express with a 2x2 matrix.
     /// In this case, the ITK image conservs this information and is identical to the MITK image!
     /// If the MITK image contains any other rotation, the ITK image will have no rotation at all.
     /// Spacing is of course conserved in both cases.
 
     // the following loop devides by spacing now to normalize columns.
     // counterpart of InitializeByItk in mitkImage.h line 372 of revision 15092.
 
     // Check if information is lost
     if (  VImageDimension == 2)
     {
       if (  ( geoMatrix[0][2] != 0) ||
         ( geoMatrix[1][2] != 0) ||
         ( geoMatrix[2][0] != 0) ||
         ( geoMatrix[2][1] != 0) ||
         (( geoMatrix[2][2] != 1) &&  ( geoMatrix[2][2] != -1) ))
       {
         // The 2D MITK image contains 3D rotation information.
         // This cannot be expressed in a 2D ITK image, so the ITK image will have no rotation
       }
       else
       {
         // The 2D MITK image can be converted to an 2D ITK image without information loss!
         for ( i=0; i < 2; ++i)
         {
           for( j=0; j < 2; ++j )
           {
             matrix[i][j] = geoMatrix[i][j]/fieldSpacing[j];
           }
         }
       }
     }
     else if (VImageDimension == 3)
     {
       // Normal 3D image. Conversion possible without problem!
       for ( i=0; i < 3; ++i)
       {
         for( j=0; j < 3; ++j )
         {
           matrix[i][j] = geoMatrix[i][j]/fieldSpacing[j];
         }
       }
     }
     else
     {
       assert(0);
       throw mitk::AccessByItkException("Usage of resultGeometry for 2D images is not yet implemented.");
       /**@TODO Implement extraction of 2D-Rotation-Matrix out of 3D-Rotation-Matrix
       * to cover this case as well.
       * matrix = extract2DRotationMatrix(resultGeometry)*/
     }
 
     resultDescriptor->setOrigin(origin);
     resultDescriptor->setSize(size);
     resultDescriptor->setSpacing(fieldSpacing);
     resultDescriptor->setDirection(matrix);
   }
 
   //do the mapping
   /////////////////////////
   typedef ::itk::InterpolateImageFunction< ::itk::Image<TPixelType,VImageDimension> > BaseInterpolatorType;
   typename BaseInterpolatorType::Pointer interpolator = generateInterpolator< ::itk::Image<TPixelType,VImageDimension> >(interpolatorType);
   assert(interpolator.IsNotNull());
   spTask->setImageInterpolator(interpolator);
   spTask->setInputImage(input);
   spTask->setRegistration(castedReg);
   spTask->setResultImageDescriptor(resultDescriptor);
   spTask->setThrowOnMappingError(throwOnMappingError);
   spTask->setErrorValue(errorValue);
   spTask->setThrowOnPaddingError(throwOnOutOfInputAreaError);
   spTask->setPaddingValue(paddingValue);
 
   spTask->execute();
   mitk::CastToMitkImage<>(spTask->getResultImage(),result);
 }
 
 
 /**Helper function to ensure the mapping of all time steps of an image.*/
 void doMapTimesteps(const mitk::ImageMappingHelper::InputImageType* input, mitk::Image* result, const mitk::ImageMappingHelper::RegistrationType* registration, bool throwOnOutOfInputAreaError,double paddingValue, const mitk::ImageMappingHelper::ResultImageGeometryType* resultGeometry, bool throwOnMappingError, double errorValue, mitk::ImageMappingInterpolator::Type interpolatorType)
 {
   for (unsigned int i = 0; i<input->GetTimeSteps(); ++i)
   {
     mitk::ImageTimeSelector::Pointer imageTimeSelector = mitk::ImageTimeSelector::New();
     imageTimeSelector->SetInput(input);
     imageTimeSelector->SetTimeNr(i);
     imageTimeSelector->UpdateLargestPossibleRegion();
 
     mitk::ImageMappingHelper::InputImageType::Pointer timeStepInput = imageTimeSelector->GetOutput();
     mitk::ImageMappingHelper::ResultImageType::Pointer timeStepResult;
     AccessByItk_n(timeStepInput, doMITKMap, (timeStepResult, registration, throwOnOutOfInputAreaError, paddingValue, resultGeometry, throwOnMappingError, errorValue, interpolatorType));
     mitk::ImageReadAccessor readAccess(timeStepResult);
     result->SetVolume(readAccess.GetData(), i);
   }
 }
 
 mitk::TimeGeometry::Pointer CreateResultTimeGeometry(const mitk::ImageMappingHelper::InputImageType* input, const mitk::ImageMappingHelper::ResultImageGeometryType* resultGeometry)
 {
   mitk::TimeGeometry::ConstPointer timeGeometry = input->GetTimeGeometry();
   mitk::TimeGeometry::Pointer mappedTimeGeometry = timeGeometry->Clone();
 
   for (unsigned int i = 0; i < input->GetTimeSteps(); ++i)
   {
     mitk::ImageMappingHelper::ResultImageGeometryType::Pointer mappedGeometry = resultGeometry->Clone();
     mappedTimeGeometry->SetTimeStepGeometry(mappedGeometry, i);
   }
   return mappedTimeGeometry;
 }
 
 mitk::ImageMappingHelper::ResultImageType::Pointer
   mitk::ImageMappingHelper::map(const InputImageType* input, const RegistrationType* registration,
   bool throwOnOutOfInputAreaError, const double& paddingValue, const ResultImageGeometryType* resultGeometry,
   bool throwOnMappingError, const double& errorValue, mitk::ImageMappingInterpolator::Type interpolatorType)
 {
   if (!registration)
   {
     mitkThrow() << "Cannot map image. Passed registration wrapper pointer is nullptr.";
   }
   if (!input)
   {
     mitkThrow() << "Cannot map image. Passed image pointer is nullptr.";
   }
 
   ResultImageType::Pointer result;
 
   auto inputLabelSetImage = dynamic_cast<const LabelSetImage*>(input);
 
   if (nullptr == inputLabelSetImage)
   {
     if (input->GetTimeSteps() == 1)
     { //map the image and done
       AccessByItk_n(input, doMITKMap, (result, registration, throwOnOutOfInputAreaError, paddingValue, resultGeometry, throwOnMappingError, errorValue, interpolatorType));
     }
     else
     { //map every time step and compose
 
       auto mappedTimeGeometry = CreateResultTimeGeometry(input, resultGeometry);
       result = mitk::Image::New();
       result->Initialize(input->GetPixelType(), *mappedTimeGeometry, 1, input->GetTimeSteps());
 
       doMapTimesteps(input, result, registration, throwOnOutOfInputAreaError, paddingValue, resultGeometry, throwOnMappingError, errorValue, interpolatorType);
     }
   }
   else
   {
     auto resultLabelSetImage = LabelSetImage::New();
 
     auto mappedTimeGeometry = CreateResultTimeGeometry(input, resultGeometry);
 
     auto resultTemplate = mitk::Image::New();
     resultTemplate->Initialize(input->GetPixelType(), *mappedTimeGeometry, 1, input->GetTimeSteps());
 
     resultLabelSetImage->Initialize(resultTemplate);
 
     auto cloneInput = inputLabelSetImage->Clone();
     //We need to clone the LabelSetImage due to its illposed design. It is state full
     //and we have to iterate through all layers as active layers to ensure the content
     //was really stored (directly working with the layer images does not work with the
     //active layer). The clone wastes rescources but is the easiest and safest way to
     //ensure 1) correct mapping 2) avoid race conditions with other parts of the
     //application because we would change the state of the input.
     //This whole code block should be reworked as soon as T28525 is done.
 
     for (unsigned int layerID = 0; layerID < inputLabelSetImage->GetNumberOfLayers(); ++layerID)
     {
       if (resultLabelSetImage->GetNumberOfLayers() <= layerID)
       {
         resultLabelSetImage->AddLayer();
       }
-      resultLabelSetImage->AddLabelSetToLayer(layerID, inputLabelSetImage->GetLabelSet(layerID)->Clone());
+      resultLabelSetImage->ReplaceGroupLabels(layerID, inputLabelSetImage->GetConstLabelsInGroup(layerID));
       cloneInput->SetActiveLayer(layerID);
       resultLabelSetImage->SetActiveLayer(layerID);
 
       doMapTimesteps(cloneInput, resultLabelSetImage, registration, throwOnOutOfInputAreaError, paddingValue, resultGeometry, throwOnMappingError, errorValue, mitk::ImageMappingInterpolator::Linear);
     }
 
     resultLabelSetImage->SetActiveLayer(inputLabelSetImage->GetActiveLayer());
-    resultLabelSetImage->GetLabelSet(inputLabelSetImage->GetActiveLayer())->SetActiveLabel(inputLabelSetImage->GetActiveLabel(inputLabelSetImage->GetActiveLayer())->GetValue());
+    resultLabelSetImage->SetActiveLabel(inputLabelSetImage->GetActiveLabel()->GetValue());
     result = resultLabelSetImage;
   }
 
   return result;
 }
 
 mitk::ImageMappingHelper::ResultImageType::Pointer
   mitk::ImageMappingHelper::map(const InputImageType* input, const MITKRegistrationType* registration,
   bool throwOnOutOfInputAreaError, const double& paddingValue, const ResultImageGeometryType* resultGeometry,
   bool throwOnMappingError, const double& errorValue, mitk::ImageMappingInterpolator::Type)
 {
   if (!registration)
   {
     mitkThrow() << "Cannot map image. Passed registration wrapper pointer is nullptr.";
   }
   if (!registration->GetRegistration())
   {
     mitkThrow() << "Cannot map image. Passed registration wrapper containes no registration.";
   }
   if (!input)
   {
     mitkThrow() << "Cannot map image. Passed image pointer is nullptr.";
   }
 
   ResultImageType::Pointer result = map(input, registration->GetRegistration(), throwOnOutOfInputAreaError, paddingValue, resultGeometry, throwOnMappingError, errorValue);
   return result;
 }
 
 mitk::ImageMappingHelper::ResultImageGeometryType::Pointer
 mitk::ImageMappingHelper::GenerateSuperSampledGeometry(const ResultImageGeometryType* inputGeometry, double xScaling, double yScaling, double zScaling)
 {
   auto resultGeometry = inputGeometry->Clone();
 
   //change the pixel count and  spacing of the geometry
   mitk::BaseGeometry::BoundsArrayType geoBounds = inputGeometry->GetBounds();
   auto oldSpacing = inputGeometry->GetSpacing();
   mitk::Vector3D geoSpacing;
 
   geoSpacing[0] = oldSpacing[0] / xScaling;
   geoSpacing[1] = oldSpacing[1] / yScaling;
   geoSpacing[2] = oldSpacing[2] / zScaling;
 
   geoBounds[1] = geoBounds[1] * xScaling;
   geoBounds[3] = geoBounds[3] * yScaling;
   geoBounds[5] = geoBounds[5] * zScaling;
 
   resultGeometry->SetBounds(geoBounds);
   resultGeometry->SetSpacing(geoSpacing);
 
   auto oldOrigin = inputGeometry->GetOrigin();
 
   //if we change the spacing we must also correct the origin to ensure
   //that the voxel matrix still covers the same space. This is due the fact
   //that the origin is not in the corner of the voxel matrix, but in the center
   // of the voxel that is in the corner.
   mitk::Point3D newOrigin;
   for (mitk::Point3D::SizeType i = 0; i < 3; ++i)
   {
     newOrigin[i] = 0.5 * (geoSpacing[i] - oldSpacing[i]) + oldOrigin[i];
   }
 
   return resultGeometry;
 }
 
 
 mitk::ImageMappingHelper::ResultImageType::Pointer
   mitk::ImageMappingHelper::
   refineGeometry(const InputImageType * input, const RegistrationType * registration,
     bool throwOnError)
 {
   mitk::ImageMappingHelper::ResultImageType::Pointer result = nullptr;
 
   if (!registration)
   {
     mitkThrow() << "Cannot refine image geometry. Passed registration pointer is nullptr.";
   }
   if (!input)
   {
     mitkThrow() << "Cannot refine image geometry. Passed image pointer is nullptr.";
   }
 
   mitk::MITKRegistrationHelper::Affine3DTransformType::Pointer spTransform = mitk::MITKRegistrationHelper::getAffineMatrix(registration, false);
   if (spTransform.IsNull() && throwOnError)
   {
     mitkThrow() << "Cannot refine image geometry. Registration does not contain a suitable direct mapping kernel (3D affine transformation or compatible required).";
   }
 
   if (spTransform.IsNotNull())
   {
     //copy input image
     result = input->Clone();
 
     //refine geometries
     for (unsigned int i = 0; i < result->GetTimeSteps(); ++i)
     { //refine every time step
       result->GetGeometry(i)->Compose(spTransform);
     }
     result->GetTimeGeometry()->Update();
   }
 
   return result;
 }
 
 
 
 mitk::ImageMappingHelper::ResultImageType::Pointer
   mitk::ImageMappingHelper::
   refineGeometry(const InputImageType* input, const MITKRegistrationType* registration,
   bool throwOnError)
 {
   if (!registration)
   {
     mitkThrow() << "Cannot refine image geometry. Passed registration wrapper pointer is nullptr.";
   }
   if (!registration->GetRegistration())
   {
     mitkThrow() << "Cannot refine image geometry. Passed registration wrapper containes no registration.";
   }
   if (!input)
   {
     mitkThrow() << "Cannot refine image geometry. Passed image pointer is nullptr.";
   }
 
   ResultImageType::Pointer result = refineGeometry(input, registration->GetRegistration(), throwOnError);
   return result;
 }
 
 bool
   mitk::ImageMappingHelper::
   canRefineGeometry(const RegistrationType* registration)
 {
   bool result = true;
 
   if (!registration)
   {
     mitkThrow() << "Cannot check refine capability of registration. Passed registration pointer is nullptr.";
   }
 
   //if the helper does not return null, we can refine the geometry.
   result = mitk::MITKRegistrationHelper::getAffineMatrix(registration,false).IsNotNull();
 
   return result;
 }
 
 bool
   mitk::ImageMappingHelper::
   canRefineGeometry(const MITKRegistrationType* registration)
 {
   if (!registration)
   {
     mitkThrow() << "Cannot check refine capability of registration. Passed registration wrapper pointer is nullptr.";
   }
   if (!registration->GetRegistration())
   {
     mitkThrow() << "Cannot check refine capability of registration. Passed registration wrapper containes no registration.";
   }
 
   return canRefineGeometry(registration->GetRegistration());
 }
 
diff --git a/Modules/Multilabel/autoload/DICOMSegIO/mitkDICOMSegmentationIO.cpp b/Modules/Multilabel/autoload/DICOMSegIO/mitkDICOMSegmentationIO.cpp
index d7a1a54de9..cec7e14e05 100644
--- a/Modules/Multilabel/autoload/DICOMSegIO/mitkDICOMSegmentationIO.cpp
+++ b/Modules/Multilabel/autoload/DICOMSegIO/mitkDICOMSegmentationIO.cpp
@@ -1,699 +1,697 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef __mitkDICOMSegmentationIO__cpp
 #define __mitkDICOMSegmentationIO__cpp
 
 #include "mitkDICOMSegmentationIO.h"
 
 #include "mitkDICOMSegIOMimeTypes.h"
 #include "mitkDICOMSegmentationConstants.h"
 #include <mitkDICOMDCMTKTagScanner.h>
 #include <mitkDICOMIOHelper.h>
 #include <mitkDICOMProperty.h>
 #include <mitkIDICOMTagsOfInterest.h>
 #include <mitkImageAccessByItk.h>
 #include <mitkImageCast.h>
 #include <mitkLocaleSwitch.h>
 #include <mitkPropertyNameHelper.h>
 
 
 // itk
 #include <itkThresholdImageFilter.h>
 
 // dcmqi
 #include <dcmqi/ImageSEGConverter.h>
 
 // us
 #include <usGetModuleContext.h>
 #include <usModuleContext.h>
 
 namespace mitk
 {
   DICOMSegmentationIO::DICOMSegmentationIO()
     : AbstractFileIO(LabelSetImage::GetStaticNameOfClass(),
       mitk::MitkDICOMSEGIOMimeTypes::DICOMSEG_MIMETYPE_NAME(),
       "DICOM Segmentation")
   {
     AbstractFileWriter::SetRanking(10);
     AbstractFileReader::SetRanking(10);
     this->RegisterService();
   }
 
   std::vector<mitk::DICOMTagPath> DICOMSegmentationIO::GetDICOMTagsOfInterest()
   {
     std::vector<mitk::DICOMTagPath> result;
     result.emplace_back(DICOMSegmentationConstants::SEGMENT_SEQUENCE_PATH());
 
     result.emplace_back(DICOMSegmentationConstants::SEGMENT_NUMBER_PATH());
     result.emplace_back(DICOMSegmentationConstants::SEGMENT_LABEL_PATH());
     result.emplace_back(DICOMSegmentationConstants::SEGMENT_ALGORITHM_TYPE_PATH());
 
     result.emplace_back(DICOMSegmentationConstants::ANATOMIC_REGION_SEQUENCE_PATH());
     result.emplace_back(DICOMSegmentationConstants::ANATOMIC_REGION_CODE_VALUE_PATH());
     result.emplace_back(DICOMSegmentationConstants::ANATOMIC_REGION_CODE_SCHEME_PATH());
     result.emplace_back(DICOMSegmentationConstants::ANATOMIC_REGION_CODE_MEANING_PATH());
 
     result.emplace_back(DICOMSegmentationConstants::SEGMENTED_PROPERTY_CATEGORY_SEQUENCE_PATH());
     result.emplace_back(DICOMSegmentationConstants::SEGMENT_CATEGORY_CODE_VALUE_PATH());
     result.emplace_back(DICOMSegmentationConstants::SEGMENT_CATEGORY_CODE_SCHEME_PATH());
     result.emplace_back(DICOMSegmentationConstants::SEGMENT_CATEGORY_CODE_MEANING_PATH());
 
     result.emplace_back(DICOMSegmentationConstants::SEGMENTED_PROPERTY_TYPE_SEQUENCE_PATH());
     result.emplace_back(DICOMSegmentationConstants::SEGMENT_TYPE_CODE_VALUE_PATH());
     result.emplace_back(DICOMSegmentationConstants::SEGMENT_TYPE_CODE_SCHEME_PATH());
     result.emplace_back(DICOMSegmentationConstants::SEGMENT_TYPE_CODE_MEANING_PATH());
 
     result.emplace_back(DICOMSegmentationConstants::SEGMENTED_PROPERTY_MODIFIER_SEQUENCE_PATH());
     result.emplace_back(DICOMSegmentationConstants::SEGMENT_MODIFIER_CODE_VALUE_PATH());
     result.emplace_back(DICOMSegmentationConstants::SEGMENT_MODIFIER_CODE_SCHEME_PATH());
     result.emplace_back(DICOMSegmentationConstants::SEGMENT_MODIFIER_CODE_MEANING_PATH());
 
     return result;
   }
 
   IFileIO::ConfidenceLevel DICOMSegmentationIO::GetWriterConfidenceLevel() const
   {
     if (AbstractFileIO::GetWriterConfidenceLevel() == Unsupported)
       return Unsupported;
 
     // Check if the input file is a segmentation
     const LabelSetImage *input = dynamic_cast<const LabelSetImage *>(this->GetInput());
 
     if (input)
     {
       if ((input->GetDimension() != 3))
       {
         MITK_INFO << "DICOM segmentation writer is tested only with 3D images, sorry.";
         return Unsupported;
       }
 
       // Check if input file has dicom information for the referenced image (original DICOM image, e.g. CT) Still necessary, see write()
       mitk::StringLookupTableProperty::Pointer dicomFilesProp =
       dynamic_cast<mitk::StringLookupTableProperty *>(input->GetProperty("referenceFiles").GetPointer());
 
       if (dicomFilesProp.IsNotNull())
         return Supported;
     }
 
     return Unsupported;
   }
 
   void DICOMSegmentationIO::Write()
   {
     ValidateOutputLocation();
 
     mitk::LocaleSwitch localeSwitch("C");
     LocalFile localFile(this);
     const std::string path = localFile.GetFileName();
 
     auto input = dynamic_cast<const LabelSetImage *>(this->GetInput());
     if (input == nullptr)
       mitkThrow() << "Cannot write non-image data";
 
     // Get DICOM information from referenced image
     vector<std::unique_ptr<DcmDataset>> dcmDatasetsSourceImage;
     std::unique_ptr<DcmFileFormat> readFileFormat(new DcmFileFormat());
     try
     {
       // TODO: Generate dcmdataset witk DICOM tags from property list; ATM the source are the filepaths from the
       // property list
       mitk::StringLookupTableProperty::Pointer filesProp =
         dynamic_cast<mitk::StringLookupTableProperty *>(input->GetProperty("referenceFiles").GetPointer());
 
       if (filesProp.IsNull())
       {
         mitkThrow() << "No property with dicom file path.";
         return;
       }
 
       StringLookupTable filesLut = filesProp->GetValue();
       const StringLookupTable::LookupTableType &lookUpTableMap = filesLut.GetLookupTable();
 
       for (const auto &it : lookUpTableMap)
       {
         const char *fileName = (it.second).c_str();
         if (readFileFormat->loadFile(fileName, EXS_Unknown).good())
         {
           std::unique_ptr<DcmDataset> readDCMDataset(readFileFormat->getAndRemoveDataset());
           dcmDatasetsSourceImage.push_back(std::move(readDCMDataset));
         }
       }
     }
     catch (const std::exception &e)
     {
       MITK_ERROR << "An error occurred while getting the dicom informations: " << e.what() << endl;
       return;
     }
 
     // Iterate over all layers. For each a dcm file will be generated
     for (unsigned int layer = 0; layer < input->GetNumberOfLayers(); ++layer)
     {
       vector<itkInternalImageType::Pointer> segmentations;
 
       try
       {
         // Hack: Remove the const attribute to switch between the layer images. Normally you could get the different
         // layer images by input->GetLayerImage(layer)
         mitk::LabelSetImage *mitkLayerImage = const_cast<mitk::LabelSetImage *>(input);
         mitkLayerImage->SetActiveLayer(layer);
 
         // Cast mitk layer image to itk
         ImageToItk<itkInputImageType>::Pointer imageToItkFilter = ImageToItk<itkInputImageType>::New();
         imageToItkFilter->SetInput(mitkLayerImage);
         // Cast from original itk type to dcmqi input itk image type
         typedef itk::CastImageFilter<itkInputImageType, itkInternalImageType> castItkImageFilterType;
         castItkImageFilterType::Pointer castFilter = castItkImageFilterType::New();
         castFilter->SetInput(imageToItkFilter->GetOutput());
         castFilter->Update();
 
         itkInternalImageType::Pointer itkLabelImage = castFilter->GetOutput();
         itkLabelImage->DisconnectPipeline();
 
         // Iterate over all labels. For each label a segmentation image will be created
-        const LabelSet *labelSet = input->GetLabelSet(layer);
+        auto labelSet = input->GetConstLabelsInGroup(layer);
 
-        for (auto labelIter = labelSet->IteratorConstBegin(); labelIter != labelSet->IteratorConstEnd(); ++labelIter)
+        for (const auto label : labelSet)
         {
           // Thresold over the image with the given label value
           itk::ThresholdImageFilter<itkInternalImageType>::Pointer thresholdFilter =
             itk::ThresholdImageFilter<itkInternalImageType>::New();
           thresholdFilter->SetInput(itkLabelImage);
-          thresholdFilter->ThresholdOutside(labelIter->first, labelIter->first);
+          thresholdFilter->ThresholdOutside(label->GetValue(), label->GetValue());
           thresholdFilter->SetOutsideValue(0);
           thresholdFilter->Update();
           itkInternalImageType::Pointer segmentImage = thresholdFilter->GetOutput();
           segmentImage->DisconnectPipeline();
 
           segmentations.push_back(segmentImage);
         }
       }
       catch (const itk::ExceptionObject &e)
       {
         MITK_ERROR << e.GetDescription() << endl;
         return;
       }
 
       // Create segmentation meta information
       const std::string tmpMetaInfoFile = this->CreateMetaDataJsonFile(layer);
 
       MITK_INFO << "Writing image: " << path << std::endl;
       try
       {
         //TODO is there a better way? Interface expects a vector of raw pointer.
         vector<DcmDataset*> rawVecDataset;
         for (const auto& dcmDataSet : dcmDatasetsSourceImage)
           rawVecDataset.push_back(dcmDataSet.get());
 
         // Convert itk segmentation images to dicom image
         std::unique_ptr<dcmqi::ImageSEGConverter> converter = std::make_unique<dcmqi::ImageSEGConverter>();
         std::unique_ptr<DcmDataset> result(converter->itkimage2dcmSegmentation(rawVecDataset, segmentations, tmpMetaInfoFile, false));
 
         // Write dicom file
         DcmFileFormat dcmFileFormat(result.get());
 
         std::string filePath = path.substr(0, path.find_last_of("."));
         // If there is more than one layer, we have to write more than 1 dicom file
         if (input->GetNumberOfLayers() != 1)
           filePath = filePath + std::to_string(layer) + ".dcm";
         else
           filePath = filePath + ".dcm";
 
         dcmFileFormat.saveFile(filePath.c_str(), EXS_LittleEndianExplicit);
       }
       catch (const std::exception &e)
       {
         MITK_ERROR << "An error occurred during writing the DICOM Seg: " << e.what() << endl;
         return;
       }
     } // Write a dcm file for the next layer
   }
 
   IFileIO::ConfidenceLevel DICOMSegmentationIO::GetReaderConfidenceLevel() const
   {
     if (AbstractFileIO::GetReaderConfidenceLevel() == Unsupported)
       return Unsupported;
 
     const std::string fileName = this->GetLocalFileName();
 
     DcmFileFormat dcmFileFormat;
     OFCondition status = dcmFileFormat.loadFile(fileName.c_str());
 
     if (status.bad())
       return Unsupported;
 
     OFString modality;
     if (dcmFileFormat.getDataset()->findAndGetOFString(DCM_Modality, modality).good())
     {
       if (modality.compare("SEG") == 0)
         return Supported;
       else
         return Unsupported;
     }
     return Unsupported;
   }
 
   std::vector<BaseData::Pointer> DICOMSegmentationIO::DoRead()
   {
     mitk::LocaleSwitch localeSwitch("C");
 
     LabelSetImage::Pointer labelSetImage;
     std::vector<BaseData::Pointer> result;
 
     const std::string path = this->GetLocalFileName();
 
     MITK_INFO << "loading " << path << std::endl;
 
     if (path.empty())
       mitkThrow() << "Empty filename in mitk::ItkImageIO ";
 
     try
     {
       // Get the dcm data set from file path
       DcmFileFormat dcmFileFormat;
       OFCondition status = dcmFileFormat.loadFile(path.c_str());
       if (status.bad())
         mitkThrow() << "Can't read the input file!";
 
       DcmDataset *dataSet = dcmFileFormat.getDataset();
       if (dataSet == nullptr)
         mitkThrow() << "Can't read data from input file!";
 
       //=============================== dcmqi part ====================================
       // Read the DICOM SEG images (segItkImages) and DICOM tags (metaInfo)
       std::unique_ptr<dcmqi::ImageSEGConverter> converter = std::make_unique<dcmqi::ImageSEGConverter>();
       pair<map<unsigned, itkInternalImageType::Pointer>, string> dcmqiOutput =
         converter->dcmSegmentation2itkimage(dataSet);
 
       map<unsigned, itkInternalImageType::Pointer> segItkImages = dcmqiOutput.first;
 
       dcmqi::JSONSegmentationMetaInformationHandler metaInfo(dcmqiOutput.second.c_str());
       metaInfo.read();
 
       MITK_INFO << "Input " << metaInfo.getJSONOutputAsString();
       //===============================================================================
 
       // Get the label information from segment attributes for each itk image
       vector<map<unsigned, dcmqi::SegmentAttributes *>>::const_iterator segmentIter =
         metaInfo.segmentsAttributesMappingList.begin();
 
       // For each itk image add a layer to the LabelSetImage output
       for (auto &element : segItkImages)
       {
         // Get the labeled image and cast it to mitkImage
         typedef itk::CastImageFilter<itkInternalImageType, itkInputImageType> castItkImageFilterType;
         castItkImageFilterType::Pointer castFilter = castItkImageFilterType::New();
         castFilter->SetInput(element.second);
         castFilter->Update();
 
         Image::Pointer layerImage;
         CastToMitkImage(castFilter->GetOutput(), layerImage);
 
         // Get pixel value of the label
         itkInternalImageType::ValueType segValue = 1;
         typedef itk::ImageRegionIterator<const itkInternalImageType> IteratorType;
         // Iterate over the image to find the pixel value of the label
         IteratorType iter(element.second, element.second->GetLargestPossibleRegion());
         iter.GoToBegin();
         while (!iter.IsAtEnd())
         {
           itkInputImageType::PixelType value = iter.Get();
           if (value != LabelSetImage::UnlabeledValue)
           {
             segValue = value;
             break;
           }
           ++iter;
         }
         // Get Segment information map
         map<unsigned, dcmqi::SegmentAttributes *> segmentMap = (*segmentIter);
         map<unsigned, dcmqi::SegmentAttributes *>::const_iterator segmentMapIter = (*segmentIter).begin();
         dcmqi::SegmentAttributes *segmentAttribute = (*segmentMapIter).second;
 
         OFString labelName;
 
         if (segmentAttribute->getSegmentedPropertyTypeCodeSequence() != nullptr)
         {
           segmentAttribute->getSegmentedPropertyTypeCodeSequence()->getCodeMeaning(labelName);
           if (segmentAttribute->getSegmentedPropertyTypeModifierCodeSequence() != nullptr)
           {
             OFString modifier;
             segmentAttribute->getSegmentedPropertyTypeModifierCodeSequence()->getCodeMeaning(modifier);
             labelName.append(" (").append(modifier).append(")");
           }
         }
         else
         {
           labelName = std::to_string(segmentAttribute->getLabelID()).c_str();
           if (labelName.empty())
             labelName = "Unnamed";
         }
 
         float tmp[3] = { 0.0, 0.0, 0.0 };
         if (segmentAttribute->getRecommendedDisplayRGBValue() != nullptr)
         {
           tmp[0] = segmentAttribute->getRecommendedDisplayRGBValue()[0] / 255.0;
           tmp[1] = segmentAttribute->getRecommendedDisplayRGBValue()[1] / 255.0;
           tmp[2] = segmentAttribute->getRecommendedDisplayRGBValue()[2] / 255.0;
         }
 
         Label *newLabel = nullptr;
         // If labelSetImage do not exists (first image)
         if (labelSetImage.IsNull())
         {
           // Initialize the labelSetImage with the read image
           labelSetImage = LabelSetImage::New();
           labelSetImage->InitializeByLabeledImage(layerImage);
           // Already a label was generated, so set the information to this
-          newLabel = labelSetImage->GetActiveLabel(labelSetImage->GetActiveLayer());
+          newLabel = labelSetImage->GetActiveLabel();
           newLabel->SetName(labelName.c_str());
           newLabel->SetColor(Color(tmp));
           newLabel->SetValue(segValue);
         }
         else
         {
           // Add a new layer to the labelSetImage. Background label is set automatically
           labelSetImage->AddLayer(layerImage);
 
           // Add new label
           newLabel = new Label;
           newLabel->SetName(labelName.c_str());
           newLabel->SetColor(Color(tmp));
           newLabel->SetValue(segValue);
-          labelSetImage->GetLabelSet(labelSetImage->GetActiveLayer())->AddLabel(newLabel);
+          labelSetImage->AddLabel(newLabel, labelSetImage->GetActiveLayer());
         }
 
         // Add some more label properties
         this->SetLabelProperties(newLabel, segmentAttribute);
         ++segmentIter;
       }
 
       labelSetImage->GetLabelSet()->SetAllLabelsVisible(true);
 
       // Add some general DICOM Segmentation properties
       mitk::IDICOMTagsOfInterest *toiSrv = DICOMIOHelper::GetTagsOfInterestService();
       auto tagsOfInterest = toiSrv->GetTagsOfInterest();
       DICOMTagPathList tagsOfInterestList;
       for (const auto &tag : tagsOfInterest)
       {
         tagsOfInterestList.push_back(tag.first);
       }
 
       mitk::DICOMDCMTKTagScanner::Pointer scanner = mitk::DICOMDCMTKTagScanner::New();
       scanner->SetInputFiles({ GetInputLocation() });
       scanner->AddTagPaths(tagsOfInterestList);
       scanner->Scan();
 
       mitk::DICOMDatasetAccessingImageFrameList frames = scanner->GetFrameInfoList();
       if (frames.empty())
       {
         MITK_ERROR << "Error reading the DICOM Seg file" << std::endl;
         return result;
       }
 
       auto findings = DICOMIOHelper::ExtractPathsOfInterest(tagsOfInterestList, frames);
       DICOMIOHelper::SetProperties(labelSetImage, findings);
 
       // Set active layer to the first layer of the labelset image
       if (labelSetImage->GetNumberOfLayers() > 1 && labelSetImage->GetActiveLayer() != 0)
         labelSetImage->SetActiveLayer(0);
     }
     catch (const std::exception &e)
     {
       MITK_ERROR << "An error occurred while reading the DICOM Seg file: " << e.what();
       return result;
     }
     catch (...)
     {
       MITK_ERROR << "An error occurred in dcmqi while reading the DICOM Seg file";
       return result;
     }
 
     result.push_back(labelSetImage.GetPointer());
     return result;
   }
 
   const std::string mitk::DICOMSegmentationIO::CreateMetaDataJsonFile(int layer)
   {
     const mitk::LabelSetImage *image = dynamic_cast<const mitk::LabelSetImage *>(this->GetInput());
 
     const std::string output;
     dcmqi::JSONSegmentationMetaInformationHandler handler;
 
 
     // 1. Metadata attributes that will be listed in the resulting DICOM SEG object
     std::string contentCreatorName;
     if (!image->GetPropertyList()->GetStringProperty(GeneratePropertyNameForDICOMTag(0x0070, 0x0084).c_str(),
       contentCreatorName))
       contentCreatorName = "MITK";
     handler.setContentCreatorName(contentCreatorName);
 
     std::string clinicalTrailSeriesId;
     if (!image->GetPropertyList()->GetStringProperty(GeneratePropertyNameForDICOMTag(0x0012, 0x0071).c_str(),
       clinicalTrailSeriesId))
       clinicalTrailSeriesId = "Session 1";
     handler.setClinicalTrialSeriesID(clinicalTrailSeriesId);
 
     std::string clinicalTrialTimePointID;
     if (!image->GetPropertyList()->GetStringProperty(GeneratePropertyNameForDICOMTag(0x0012, 0x0050).c_str(),
       clinicalTrialTimePointID))
       clinicalTrialTimePointID = "0";
     handler.setClinicalTrialTimePointID(clinicalTrialTimePointID);
 
     std::string clinicalTrialCoordinatingCenterName = "";
     if (!image->GetPropertyList()->GetStringProperty(GeneratePropertyNameForDICOMTag(0x0012, 0x0060).c_str(),
       clinicalTrialCoordinatingCenterName))
       clinicalTrialCoordinatingCenterName = "Unknown";
     handler.setClinicalTrialCoordinatingCenterName(clinicalTrialCoordinatingCenterName);
 
     std::string seriesDescription;
     if (!image->GetPropertyList()->GetStringProperty("name", seriesDescription))
       seriesDescription = "MITK Segmentation";
     handler.setSeriesDescription(seriesDescription);
 
     handler.setSeriesNumber("0" + std::to_string(layer));
     handler.setInstanceNumber("1");
     handler.setBodyPartExamined("");
 
-    const LabelSet *labelSet = image->GetLabelSet(layer);
+    auto labelSet = image->GetConstLabelsInGroup(layer);
 
-    for (auto labelIter = labelSet->IteratorConstBegin(); labelIter != labelSet->IteratorConstEnd(); ++labelIter)
+    for (const auto label : labelSet)
     {
-      const Label *label = labelIter->second;
-
       if (label != nullptr)
       {
         TemporoSpatialStringProperty *segmentNumberProp = dynamic_cast<mitk::TemporoSpatialStringProperty *>(label->GetProperty(
           mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_NUMBER_PATH()).c_str()));
 
         TemporoSpatialStringProperty *segmentLabelProp = dynamic_cast<mitk::TemporoSpatialStringProperty *>(label->GetProperty(
           mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_LABEL_PATH()).c_str()));
 
         TemporoSpatialStringProperty *algorithmTypeProp = dynamic_cast<mitk::TemporoSpatialStringProperty *>(label->GetProperty(
           mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_ALGORITHM_TYPE_PATH()).c_str()));
 
         TemporoSpatialStringProperty *segmentCategoryCodeValueProp = dynamic_cast<mitk::TemporoSpatialStringProperty *>(label->GetProperty(
           mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_CATEGORY_CODE_VALUE_PATH()).c_str()));
 
         TemporoSpatialStringProperty *segmentCategoryCodeSchemeProp = dynamic_cast<mitk::TemporoSpatialStringProperty *>(label->GetProperty(
           mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_CATEGORY_CODE_SCHEME_PATH()).c_str()));
 
         TemporoSpatialStringProperty *segmentCategoryCodeMeaningProp = dynamic_cast<mitk::TemporoSpatialStringProperty *>(label->GetProperty(
           mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_CATEGORY_CODE_MEANING_PATH()).c_str()));
 
         TemporoSpatialStringProperty *segmentTypeCodeValueProp = dynamic_cast<mitk::TemporoSpatialStringProperty *>(label->GetProperty(
           mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_TYPE_CODE_VALUE_PATH()).c_str()));
 
         TemporoSpatialStringProperty *segmentTypeCodeSchemeProp = dynamic_cast<mitk::TemporoSpatialStringProperty *>(label->GetProperty(
           mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_TYPE_CODE_SCHEME_PATH()).c_str()));
 
         TemporoSpatialStringProperty *segmentTypeCodeMeaningProp = dynamic_cast<mitk::TemporoSpatialStringProperty *>(label->GetProperty(
           mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_TYPE_CODE_MEANING_PATH()).c_str()));
 
         TemporoSpatialStringProperty *segmentModifierCodeValueProp = dynamic_cast<mitk::TemporoSpatialStringProperty *>(label->GetProperty(
           mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_MODIFIER_CODE_VALUE_PATH()).c_str()));
 
         TemporoSpatialStringProperty *segmentModifierCodeSchemeProp = dynamic_cast<mitk::TemporoSpatialStringProperty *>(label->GetProperty(
           mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_MODIFIER_CODE_SCHEME_PATH()).c_str()));
 
         TemporoSpatialStringProperty *segmentModifierCodeMeaningProp = dynamic_cast<mitk::TemporoSpatialStringProperty *>(label->GetProperty(
           mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_MODIFIER_CODE_MEANING_PATH()).c_str()));
 
         dcmqi::SegmentAttributes *segmentAttribute = nullptr;
 
         if (segmentNumberProp->GetValue() == "")
         {
           MITK_ERROR << "Something went wrong with the label ID.";
         }
         else
         {
           int labelId = std::stoi(segmentNumberProp->GetValue());
           segmentAttribute = handler.createAndGetNewSegment(labelId);
         }
         if (segmentAttribute != nullptr)
         {
           segmentAttribute->setSegmentLabel(segmentLabelProp->GetValueAsString());
           segmentAttribute->setSegmentDescription(segmentLabelProp->GetValueAsString());
           segmentAttribute->setSegmentAlgorithmType(algorithmTypeProp->GetValueAsString());
           segmentAttribute->setSegmentAlgorithmName("MITK Segmentation");
           if (segmentCategoryCodeValueProp != nullptr && segmentCategoryCodeSchemeProp != nullptr &&
             segmentCategoryCodeMeaningProp != nullptr)
             segmentAttribute->setSegmentedPropertyCategoryCodeSequence(
               segmentCategoryCodeValueProp->GetValueAsString(),
               segmentCategoryCodeSchemeProp->GetValueAsString(),
               segmentCategoryCodeMeaningProp->GetValueAsString());
           else
             // some default values
             segmentAttribute->setSegmentedPropertyCategoryCodeSequence(
               "M-01000", "SRT", "Morphologically Altered Structure");
 
           if (segmentTypeCodeValueProp != nullptr && segmentTypeCodeSchemeProp != nullptr &&
             segmentTypeCodeMeaningProp != nullptr)
           {
             segmentAttribute->setSegmentedPropertyTypeCodeSequence(segmentTypeCodeValueProp->GetValueAsString(),
               segmentTypeCodeSchemeProp->GetValueAsString(),
               segmentTypeCodeMeaningProp->GetValueAsString());
             handler.setBodyPartExamined(segmentTypeCodeMeaningProp->GetValueAsString());
           }
           else
           {
             // some default values
             segmentAttribute->setSegmentedPropertyTypeCodeSequence("M-03000", "SRT", "Mass");
             handler.setBodyPartExamined("Mass");
           }
           if (segmentModifierCodeValueProp != nullptr && segmentModifierCodeSchemeProp != nullptr &&
             segmentModifierCodeMeaningProp != nullptr)
             segmentAttribute->setSegmentedPropertyTypeModifierCodeSequence(
               segmentModifierCodeValueProp->GetValueAsString(),
               segmentModifierCodeSchemeProp->GetValueAsString(),
               segmentModifierCodeMeaningProp->GetValueAsString());
 
           Color color = label->GetColor();
           segmentAttribute->setRecommendedDisplayRGBValue(color[0] * 255, color[1] * 255, color[2] * 255);
         }
       }
     }
     return handler.getJSONOutputAsString();
   }
 
   void mitk::DICOMSegmentationIO::SetLabelProperties(mitk::Label *label, dcmqi::SegmentAttributes *segmentAttribute)
   {
     // Segment Number:Identification number of the segment.The value of Segment Number(0062, 0004) shall be unique
     // within the Segmentation instance in which it is created
     label->SetProperty(DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_NUMBER_PATH()).c_str(),
       TemporoSpatialStringProperty::New(std::to_string(label->GetValue())));
 
     // Segment Label: User-defined label identifying this segment.
     label->SetProperty(DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_LABEL_PATH()).c_str(),
       TemporoSpatialStringProperty::New(label->GetName()));
 
     // Segment Algorithm Type: Type of algorithm used to generate the segment.
     if (!segmentAttribute->getSegmentAlgorithmType().empty())
       label->SetProperty(DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_ALGORITHM_TYPE_PATH()).c_str(),
         TemporoSpatialStringProperty::New(segmentAttribute->getSegmentAlgorithmType()));
 
     // Add Segmented Property Category Code Sequence tags
     auto categoryCodeSequence = segmentAttribute->getSegmentedPropertyCategoryCodeSequence();
     if (categoryCodeSequence != nullptr)
     {
       OFString codeValue; // (0008,0100) Code Value
       categoryCodeSequence->getCodeValue(codeValue);
       label->SetProperty(
         DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_CATEGORY_CODE_VALUE_PATH()).c_str(),
         TemporoSpatialStringProperty::New(codeValue.c_str()));
 
       OFString codeScheme; // (0008,0102) Coding Scheme Designator
       categoryCodeSequence->getCodingSchemeDesignator(codeScheme);
       label->SetProperty(
         DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_CATEGORY_CODE_SCHEME_PATH()).c_str(),
         TemporoSpatialStringProperty::New(codeScheme.c_str()));
 
       OFString codeMeaning; // (0008,0104) Code Meaning
       categoryCodeSequence->getCodeMeaning(codeMeaning);
       label->SetProperty(
         DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_CATEGORY_CODE_MEANING_PATH()).c_str(),
         TemporoSpatialStringProperty::New(codeMeaning.c_str()));
     }
 
     // Add Segmented Property Type Code Sequence tags
     auto typeCodeSequence = segmentAttribute->getSegmentedPropertyTypeCodeSequence();
     if (typeCodeSequence != nullptr)
     {
       OFString codeValue; // (0008,0100) Code Value
       typeCodeSequence->getCodeValue(codeValue);
       label->SetProperty(DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_TYPE_CODE_VALUE_PATH()).c_str(),
         TemporoSpatialStringProperty::New(codeValue.c_str()));
 
       OFString codeScheme; // (0008,0102) Coding Scheme Designator
       typeCodeSequence->getCodingSchemeDesignator(codeScheme);
       label->SetProperty(
         DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_TYPE_CODE_SCHEME_PATH()).c_str(),
         TemporoSpatialStringProperty::New(codeScheme.c_str()));
 
       OFString codeMeaning; // (0008,0104) Code Meaning
       typeCodeSequence->getCodeMeaning(codeMeaning);
       label->SetProperty(
         DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_TYPE_CODE_MEANING_PATH()).c_str(),
         TemporoSpatialStringProperty::New(codeMeaning.c_str()));
     }
 
     // Add Segmented Property Type Modifier Code Sequence tags
     auto modifierCodeSequence = segmentAttribute->getSegmentedPropertyTypeModifierCodeSequence();
     if (modifierCodeSequence != nullptr)
     {
       OFString codeValue; // (0008,0100) Code Value
       modifierCodeSequence->getCodeValue(codeValue);
       label->SetProperty(
         DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_MODIFIER_CODE_VALUE_PATH()).c_str(),
         TemporoSpatialStringProperty::New(codeValue.c_str()));
 
       OFString codeScheme; // (0008,0102) Coding Scheme Designator
       modifierCodeSequence->getCodingSchemeDesignator(codeScheme);
       label->SetProperty(
         DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_MODIFIER_CODE_SCHEME_PATH()).c_str(),
         TemporoSpatialStringProperty::New(codeScheme.c_str()));
 
       OFString codeMeaning; // (0008,0104) Code Meaning
       modifierCodeSequence->getCodeMeaning(codeMeaning);
       label->SetProperty(
         DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_MODIFIER_CODE_MEANING_PATH()).c_str(),
         TemporoSpatialStringProperty::New(codeMeaning.c_str()));
     }
 
     // Add Atomic RegionSequence tags
     auto atomicRegionSequence = segmentAttribute->getAnatomicRegionSequence();
     if (atomicRegionSequence != nullptr)
     {
       OFString codeValue; // (0008,0100) Code Value
       atomicRegionSequence->getCodeValue(codeValue);
       label->SetProperty(
         DICOMTagPathToPropertyName(DICOMSegmentationConstants::ANATOMIC_REGION_CODE_VALUE_PATH()).c_str(),
         TemporoSpatialStringProperty::New(codeValue.c_str()));
 
       OFString codeScheme; // (0008,0102) Coding Scheme Designator
       atomicRegionSequence->getCodingSchemeDesignator(codeScheme);
       label->SetProperty(
         DICOMTagPathToPropertyName(DICOMSegmentationConstants::ANATOMIC_REGION_CODE_SCHEME_PATH()).c_str(),
         TemporoSpatialStringProperty::New(codeScheme.c_str()));
 
       OFString codeMeaning; // (0008,0104) Code Meaning
       atomicRegionSequence->getCodeMeaning(codeMeaning);
       label->SetProperty(
         DICOMTagPathToPropertyName(DICOMSegmentationConstants::ANATOMIC_REGION_CODE_MEANING_PATH()).c_str(),
         TemporoSpatialStringProperty::New(codeMeaning.c_str()));
     }
   }
 
   DICOMSegmentationIO *DICOMSegmentationIO::IOClone() const { return new DICOMSegmentationIO(*this); }
 } // namespace
 
 #endif //__mitkDICOMSegmentationIO__cpp
diff --git a/Modules/Multilabel/autoload/IO/mitkLegacyLabelSetImageIO.cpp b/Modules/Multilabel/autoload/IO/mitkLegacyLabelSetImageIO.cpp
index 342097f104..8c2a7ce107 100644
--- a/Modules/Multilabel/autoload/IO/mitkLegacyLabelSetImageIO.cpp
+++ b/Modules/Multilabel/autoload/IO/mitkLegacyLabelSetImageIO.cpp
@@ -1,272 +1,273 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef __mitkLabelSetImageWriter__cpp
 #define __mitkLabelSetImageWriter__cpp
 
 #include "mitkLegacyLabelSetImageIO.h"
 #include "mitkBasePropertySerializer.h"
 #include "mitkMultilabelIOMimeTypes.h"
 #include "mitkImageAccessByItk.h"
 #include "mitkMultiLabelIOHelper.h"
 #include "mitkLabelSetImageConverter.h"
 #include <mitkLocaleSwitch.h>
 #include <mitkArbitraryTimeGeometry.h>
 #include <mitkIPropertyPersistence.h>
 #include <mitkCoreServices.h>
 #include <mitkItkImageIO.h>
 #include <mitkUIDManipulator.h>
 
 // itk
 #include "itkImageFileReader.h"
 #include "itkImageFileWriter.h"
 #include "itkMetaDataDictionary.h"
 #include "itkMetaDataObject.h"
 #include "itkNrrdImageIO.h"
 
 #include <tinyxml2.h>
 
 
 namespace mitk
 {
 
   const constexpr char* const OPTION_NAME_MULTI_LAYER = "Multi layer handling";
   const constexpr char* const OPTION_NAME_MULTI_LAYER_ADAPT = "Adapt label values";
   const constexpr char* const OPTION_NAME_MULTI_LAYER_SPLIT = "Split layers";
 
   LegacyLabelSetImageIO::LegacyLabelSetImageIO()
     : AbstractFileReader(MitkMultilabelIOMimeTypes::LEGACYLABELSET_MIMETYPE(), "MITK LabelSetImage (legacy)")
   {
     this->InitializeDefaultMetaDataKeys();
     AbstractFileReader::SetRanking(10);
 
     IFileIO::Options options;
     std::vector<std::string> multiLayerStrategy;
     multiLayerStrategy.push_back(OPTION_NAME_MULTI_LAYER_ADAPT);
     multiLayerStrategy.push_back(OPTION_NAME_MULTI_LAYER_SPLIT);
     options[OPTION_NAME_MULTI_LAYER] = multiLayerStrategy;
     this->SetDefaultOptions(options);
 
     this->RegisterService();
   }
 
 
   IFileIO::ConfidenceLevel LegacyLabelSetImageIO::GetConfidenceLevel() const
   {
     if (AbstractFileReader::GetConfidenceLevel() == Unsupported)
       return Unsupported;
     const std::string fileName = this->GetLocalFileName();
     itk::NrrdImageIO::Pointer io = itk::NrrdImageIO::New();
     io->SetFileName(fileName);
     io->ReadImageInformation();
 
     itk::MetaDataDictionary imgMetaDataDictionary = io->GetMetaDataDictionary();
     std::string value("");
     itk::ExposeMetaData<std::string>(imgMetaDataDictionary, "modality", value);
     if (value.compare("org.mitk.image.multilabel") == 0)
     {
       return Supported;
     }
     else
       return Unsupported;
   }
 
-  std::vector<mitk::LabelSet::Pointer> ExtractLabelSetsFromMetaData(const itk::MetaDataDictionary& dictionary)
+  std::vector<mitk::LabelSetImage::LabelVectorType> ExtractLabelSetsFromMetaData(const itk::MetaDataDictionary& dictionary)
   {
-    std::vector<mitk::LabelSet::Pointer> result;
+    std::vector<mitk::LabelSetImage::LabelVectorType> result;
 
     // get labels and add them as properties to the image
     char keybuffer[256];
 
     unsigned int numberOfLayers = MultiLabelIOHelper::GetIntByKey(dictionary, "layers");
     std::string _xmlStr;
     mitk::Label::Pointer label;
 
     for (unsigned int layerIdx = 0; layerIdx < numberOfLayers; layerIdx++)
     {
       sprintf(keybuffer, "layer_%03u", layerIdx);
       int numberOfLabels = MultiLabelIOHelper::GetIntByKey(dictionary, keybuffer);
 
-      mitk::LabelSet::Pointer labelSet = mitk::LabelSet::New();
+      mitk::LabelSetImage::LabelVectorType labelSet;
 
       for (int labelIdx = 0; labelIdx < numberOfLabels; labelIdx++)
       {
         tinyxml2::XMLDocument doc;
         sprintf(keybuffer, "label_%03u_%05d", layerIdx, labelIdx);
         _xmlStr = MultiLabelIOHelper::GetStringByKey(dictionary, keybuffer);
         doc.Parse(_xmlStr.c_str(), _xmlStr.size());
 
         auto* labelElem = doc.FirstChildElement("Label");
         if (labelElem == nullptr)
           mitkThrow() << "Error parsing NRRD header for mitk::LabelSetImage IO";
 
         label = mitk::MultiLabelIOHelper::LoadLabelFromXMLDocument(labelElem);
 
         if (label->GetValue() != mitk::LabelSetImage::UnlabeledValue)
         {
-          labelSet->AddLabel(label);
-          labelSet->SetLayer(layerIdx);
+          labelSet.push_back(label);
         }
         else
         {
           MITK_INFO << "Multi label image contains a label specification for unlabeled pixels. This legacy information is ignored.";
         }
       }
       result.push_back(labelSet);
     }
 
     return result;
   }
 
   std::vector<BaseData::Pointer> LegacyLabelSetImageIO::DoRead()
   {
     itk::NrrdImageIO::Pointer nrrdImageIO = itk::NrrdImageIO::New();
 
     std::vector<BaseData::Pointer> result;
 
     auto rawimage = ItkImageIO::LoadRawMitkImageFromImageIO(nrrdImageIO, this->GetLocalFileName());
 
     const itk::MetaDataDictionary& dictionary = nrrdImageIO->GetMetaDataDictionary();
 
     std::vector<Image::Pointer> groupImages = { rawimage };
     if (rawimage->GetChannelDescriptor().GetPixelType().GetPixelType() == itk::IOPixelEnum::VECTOR)
     {
       groupImages = SplitVectorImage(rawimage);
     }
 
     auto labelsets = ExtractLabelSetsFromMetaData(dictionary);
 
     if (labelsets.size() != groupImages.size())
     {
       mitkThrow() << "Loaded data is in an invalid state. Number of extracted layer images and labels sets does not match. Found layer images: " << groupImages.size() << "; found labelsets: " << labelsets.size();
     }
 
     auto props = ItkImageIO::ExtractMetaDataAsPropertyList(nrrdImageIO->GetMetaDataDictionary(), this->GetMimeType()->GetName(), this->m_DefaultMetaDataKeys);
 
     const Options userOptions = this->GetOptions();
 
     const auto multiLayerStrategy = userOptions.find(OPTION_NAME_MULTI_LAYER)->second.ToString();
 
     if (multiLayerStrategy == OPTION_NAME_MULTI_LAYER_SPLIT)
     { //just split layers in different multi label images
       auto labelSetIterator = labelsets.begin();
       for (auto image : groupImages)
       {
         auto output = ConvertImageToLabelSetImage(image);
-        output->AddLabelSetToLayer(0, *labelSetIterator);
-        output->GetLabelSet(0)->SetLayer(0);
+        output->ReplaceGroupLabels(0, *labelSetIterator);
 
         //meta data handling
         for (auto& [name, prop] : *(props->GetMap()))
         {
           output->SetProperty(name, prop->Clone()); //need to clone to avoid that all outputs pointing to the same prop instances.
         }
         // Handle UID
         //Remark if we split the legacy label set into distinct layer images, the outputs should have new IDs. So we don't get the old one.
 
         result.push_back(output.GetPointer());
         labelSetIterator++;
       }
     }
     else
     { //Avoid label id collision.
       LabelSetImage::LabelValueType maxValue = LabelSetImage::UnlabeledValue;
       auto imageIterator = groupImages.begin();
-      std::vector<mitk::LabelSet::Pointer> adaptedLabelSets;
+      std::vector<mitk::LabelSetImage::LabelVectorType> adaptedLabelSets;
 
       for (auto labelset : labelsets)
       {
-        const auto setValues = labelset->GetUsedLabelValues();
+        const auto setValues = LabelSetImage::ExtractLabelValuesFromLabelVector(labelset);
 
         //generate mapping table;
         std::vector<std::pair<Label::PixelType, Label::PixelType> > labelMapping;
         for (auto vIter = setValues.crbegin(); vIter != setValues.crend(); vIter++)
         { //have to use reverse loop because TransferLabelContent (used to adapt content in the same image; see below)
           //would potentially corrupt otherwise the content due to "value collision between old values still present
           //and already adapted values. By going from highest value to lowest, we avoid that.
           if (LabelSetImage::UnlabeledValue != *vIter)
-            labelMapping.push_back({ *vIter, *vIter + maxValue });
+            labelMapping.push_back({*vIter, *vIter + maxValue});
         }
 
-
         if (LabelSetImage::UnlabeledValue != maxValue)
         {
           //adapt labelset
-          auto mappedLabelSet = GenerateLabelSetWithMappedValues(labelset, labelMapping);
+          auto mappedLabelSet = GenerateLabelSetWithMappedValues(LabelSetImage::ConvertLabelVectorConst(labelset), labelMapping);
           adaptedLabelSets.emplace_back(mappedLabelSet);
 
           //adapt image (it is an inplace operation. the image instance stays the same.
-          TransferLabelContent(*imageIterator, *imageIterator, mappedLabelSet, LabelSetImage::UnlabeledValue, LabelSetImage::UnlabeledValue,
+          TransferLabelContent(*imageIterator, *imageIterator, LabelSetImage::ConvertLabelVectorConst(mappedLabelSet), LabelSetImage::UnlabeledValue, LabelSetImage::UnlabeledValue,
             false, labelMapping, MultiLabelSegmentation::MergeStyle::Replace, MultiLabelSegmentation::OverwriteStyle::IgnoreLocks);
         }
         else
         {
           adaptedLabelSets.emplace_back(labelset);
         }
 
-        const auto setMaxValue = *(std::max_element(setValues.begin(), setValues.end()));
-        maxValue += setMaxValue;
+        const auto maxFinding = std::max_element(setValues.begin(), setValues.end());
+        if (maxFinding != setValues.end())
+        {
+          const auto setMaxValue = *(maxFinding);
+          maxValue += setMaxValue;
+        }
         imageIterator++;
       }
 
       auto output = ConvertImageVectorToLabelSetImage(groupImages, rawimage->GetTimeGeometry());
 
       LabelSetImage::GroupIndexType id = 0;
       for (auto labelset : adaptedLabelSets)
       {
-        output->AddLabelSetToLayer(id, labelset);
+        output->ReplaceGroupLabels(id, labelset);
         id++;
       }
 
       //meta data handling
       for (auto& [name, prop] : *(props->GetMap()))
       {
         output->SetProperty(name, prop->Clone()); //need to clone to avoid that all outputs pointing to the same prop instances.
       }
 
       // Handle UID
       if (dictionary.HasKey(PROPERTY_KEY_UID))
       {
         itk::MetaDataObject<std::string>::ConstPointer uidData = dynamic_cast<const itk::MetaDataObject<std::string>*>(dictionary.Get(PROPERTY_KEY_UID));
         if (uidData.IsNotNull())
         {
           mitk::UIDManipulator uidManipulator(output);
           uidManipulator.SetUID(uidData->GetMetaDataObjectValue());
         }
       }
       result.push_back(output.GetPointer());
     }
 
     MITK_INFO << "...finished!";
     return result;
   }
 
   LegacyLabelSetImageIO *LegacyLabelSetImageIO::Clone() const { return new LegacyLabelSetImageIO(*this); }
 
   void LegacyLabelSetImageIO::InitializeDefaultMetaDataKeys()
   {
     this->m_DefaultMetaDataKeys.push_back("NRRD.space");
     this->m_DefaultMetaDataKeys.push_back("NRRD.kinds");
     this->m_DefaultMetaDataKeys.push_back(PROPERTY_NAME_TIMEGEOMETRY_TYPE);
     this->m_DefaultMetaDataKeys.push_back(PROPERTY_NAME_TIMEGEOMETRY_TIMEPOINTS);
     this->m_DefaultMetaDataKeys.push_back("ITK.InputFilterName");
     this->m_DefaultMetaDataKeys.push_back("label.");
     this->m_DefaultMetaDataKeys.push_back("layer.");
     this->m_DefaultMetaDataKeys.push_back("layers");
     this->m_DefaultMetaDataKeys.push_back("modality");
     this->m_DefaultMetaDataKeys.push_back("org.mitk.label.");
     this->m_DefaultMetaDataKeys.push_back("MITK.IO.");
   }
 
 } // namespace
 
 #endif //__mitkLabelSetImageWriter__cpp
diff --git a/Modules/Multilabel/autoload/IO/mitkMultiLabelSegmentationIO.cpp b/Modules/Multilabel/autoload/IO/mitkMultiLabelSegmentationIO.cpp
index b9e9fba8ea..10d48fb82e 100644
--- a/Modules/Multilabel/autoload/IO/mitkMultiLabelSegmentationIO.cpp
+++ b/Modules/Multilabel/autoload/IO/mitkMultiLabelSegmentationIO.cpp
@@ -1,224 +1,224 @@
 /*============================================================================
 
 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 "mitkMultiLabelSegmentationIO.h"
 #include "mitkBasePropertySerializer.h"
 #include "mitkIOMimeTypes.h"
 #include "mitkImageAccessByItk.h"
 #include "mitkMultiLabelIOHelper.h"
 #include "mitkLabelSetImageConverter.h"
 #include <mitkLocaleSwitch.h>
 #include <mitkArbitraryTimeGeometry.h>
 #include <mitkIPropertyPersistence.h>
 #include <mitkCoreServices.h>
 #include <mitkItkImageIO.h>
 #include <mitkUIDManipulator.h>
 
 // itk
 #include "itkImageFileReader.h"
 #include "itkImageFileWriter.h"
 #include "itkMetaDataDictionary.h"
 #include "itkMetaDataObject.h"
 #include "itkNrrdImageIO.h"
 
 #include <tinyxml2.h>
 
 namespace mitk
 {
 
   const constexpr char* const MULTILABEL_SEGMENTATION_MODALITY_KEY = "modality";
   const constexpr char* const MULTILABEL_SEGMENTATION_MODALITY_VALUE = "org.mitk.multilabel.segmentation";
   const constexpr char* const MULTILABEL_SEGMENTATION_VERSION_KEY = "org.mitk.multilabel.segmentation.version";
   const constexpr int MULTILABEL_SEGMENTATION_VERSION_VALUE = 1;
   const constexpr char* const MULTILABEL_SEGMENTATION_LABELS_INFO_KEY = "org.mitk.multilabel.segmentation.labelgroups";
   const constexpr char* const MULTILABEL_SEGMENTATION_UNLABELEDLABEL_LOCK_KEY = "org.mitk.multilabel.segmentation.unlabeledlabellock";
 
   MultiLabelSegmentationIO::MultiLabelSegmentationIO()
     : AbstractFileIO(LabelSetImage::GetStaticNameOfClass(), IOMimeTypes::NRRD_MIMETYPE(), "MITK Multilabel Segmentation")
   {
     this->InitializeDefaultMetaDataKeys();
     AbstractFileWriter::SetRanking(10);
     AbstractFileReader::SetRanking(10);
     this->RegisterService();
   }
 
   IFileIO::ConfidenceLevel MultiLabelSegmentationIO::GetWriterConfidenceLevel() const
   {
     if (AbstractFileIO::GetWriterConfidenceLevel() == Unsupported)
       return Unsupported;
     const auto *input = static_cast<const LabelSetImage *>(this->GetInput());
     if (input)
       return Supported;
     else
       return Unsupported;
   }
 
   void MultiLabelSegmentationIO::Write()
   {
     ValidateOutputLocation();
 
     auto input = dynamic_cast<const LabelSetImage *>(this->GetInput());
 
     mitk::LocaleSwitch localeSwitch("C");
 
     mitk::Image::Pointer inputVector = mitk::ConvertLabelSetImageToImage(input);
 
     // image write
     if (inputVector.IsNull())
     {
       mitkThrow() << "Cannot write non-image data";
     }
 
     itk::NrrdImageIO::Pointer nrrdImageIo = itk::NrrdImageIO::New();
 
     ItkImageIO::PreparImageIOToWriteImage(nrrdImageIo, inputVector);
 
     LocalFile localFile(this);
     const std::string path = localFile.GetFileName();
 
     MITK_INFO << "Writing image: " << path << std::endl;
 
     try
     {
       itk::EncapsulateMetaData<std::string>(
         nrrdImageIo->GetMetaDataDictionary(), std::string(MULTILABEL_SEGMENTATION_MODALITY_KEY), std::string(MULTILABEL_SEGMENTATION_MODALITY_VALUE));
 
       //nrrd does only support string meta information. So we have to convert before.
       itk::EncapsulateMetaData<std::string>(
         nrrdImageIo->GetMetaDataDictionary(), std::string(MULTILABEL_SEGMENTATION_VERSION_KEY), std::to_string(MULTILABEL_SEGMENTATION_VERSION_VALUE));
 
       auto json = MultiLabelIOHelper::SerializeMultLabelGroupsToJSON(input);
       itk::EncapsulateMetaData<std::string>(
         nrrdImageIo->GetMetaDataDictionary(), std::string(MULTILABEL_SEGMENTATION_LABELS_INFO_KEY), json.dump());
       // end label set specific meta data
 
       //nrrd does only support string meta information. So we have to convert before.
       itk::EncapsulateMetaData<std::string>(
         nrrdImageIo->GetMetaDataDictionary(), std::string(MULTILABEL_SEGMENTATION_UNLABELEDLABEL_LOCK_KEY), std::to_string(input->GetUnlabeledLabelLock()));
 
       // Handle properties
       ItkImageIO::SavePropertyListAsMetaData(nrrdImageIo->GetMetaDataDictionary(), input->GetPropertyList(), this->GetMimeType()->GetName());
 
       // Handle UID
       itk::EncapsulateMetaData<std::string>(nrrdImageIo->GetMetaDataDictionary(), PROPERTY_KEY_UID, input->GetUID());
 
       // use compression if available
       nrrdImageIo->UseCompressionOn();
       nrrdImageIo->SetFileName(path);
 
       ImageReadAccessor imageAccess(inputVector);
       nrrdImageIo->Write(imageAccess.GetData());
     }
     catch (const std::exception &e)
     {
       mitkThrow() << e.what();
     }
   }
 
   IFileIO::ConfidenceLevel MultiLabelSegmentationIO::GetReaderConfidenceLevel() const
   {
     if (AbstractFileIO::GetReaderConfidenceLevel() == Unsupported)
       return Unsupported;
     const std::string fileName = this->GetLocalFileName();
     itk::NrrdImageIO::Pointer io = itk::NrrdImageIO::New();
     io->SetFileName(fileName);
     io->ReadImageInformation();
 
     itk::MetaDataDictionary imgMetaDataDictionary = io->GetMetaDataDictionary();
     std::string value("");
     itk::ExposeMetaData<std::string>(imgMetaDataDictionary, "modality", value);
     if (value.compare(MULTILABEL_SEGMENTATION_MODALITY_VALUE) == 0)
     {
       return Supported;
     }
     else
       return Unsupported;
   }
 
   std::vector<BaseData::Pointer> MultiLabelSegmentationIO::DoRead()
   {
     itk::NrrdImageIO::Pointer nrrdImageIO = itk::NrrdImageIO::New();
 
     std::vector<BaseData::Pointer> result;
 
     auto rawimage = ItkImageIO::LoadRawMitkImageFromImageIO(nrrdImageIO, this->GetLocalFileName());
 
     const itk::MetaDataDictionary& dictionary = nrrdImageIO->GetMetaDataDictionary();
 
     //check version
     auto version = MultiLabelIOHelper::GetIntByKey(dictionary, MULTILABEL_SEGMENTATION_VERSION_KEY);
     if (version > MULTILABEL_SEGMENTATION_VERSION_VALUE)
     {
       mitkThrow() << "Data to read has unsupported version. Software is to old to ensure correct reading. Please use a compatible version of MITK or store data in another format. Version of data: " << version << "; Supported versions up to: "<<MULTILABEL_SEGMENTATION_VERSION_VALUE;
     }
 
     //generate multi label images
     auto output = ConvertImageToLabelSetImage(rawimage);
 
     //get label set definitions
     auto jsonStr = MultiLabelIOHelper::GetStringByKey(dictionary, MULTILABEL_SEGMENTATION_LABELS_INFO_KEY);
     nlohmann::json jlabelsets = nlohmann::json::parse(jsonStr);
-    std::vector<mitk::LabelSet::Pointer> labelsets = MultiLabelIOHelper::DeserializeMultiLabelGroupsFromJSON(jlabelsets);
+    auto labelsets = MultiLabelIOHelper::DeserializeMultiLabelGroupsFromJSON(jlabelsets);
 
     if (labelsets.size() != output->GetNumberOfLayers())
     {
       mitkThrow() << "Loaded data is in an invalid state. Number of extracted layer images and labels sets does not match. Found layer images: " << output->GetNumberOfLayers() << "; found labelsets: " << labelsets.size();
     }
 
     LabelSetImage::GroupIndexType id = 0;
     for (auto labelset : labelsets)
     {
-      output->AddLabelSetToLayer(id, labelset);
+      output->ReplaceGroupLabels(id, labelset);
       id++;
     }
 
     bool unlabeledLock = MultiLabelIOHelper::GetIntByKey(dictionary, MULTILABEL_SEGMENTATION_UNLABELEDLABEL_LOCK_KEY) != 0;
     output->SetUnlabeledLabelLock(unlabeledLock);
 
     //meta data handling
     auto props = ItkImageIO::ExtractMetaDataAsPropertyList(nrrdImageIO->GetMetaDataDictionary(), this->GetMimeType()->GetName(), this->m_DefaultMetaDataKeys);
     for (auto& [name, prop] : *(props->GetMap()))
     {
       output->SetProperty(name, prop->Clone()); //need to clone to avoid that all outputs pointing to the same prop instances.
     }
 
     // Handle UID
     if (dictionary.HasKey(PROPERTY_KEY_UID))
     {
       itk::MetaDataObject<std::string>::ConstPointer uidData = dynamic_cast<const itk::MetaDataObject<std::string>*>(dictionary.Get(PROPERTY_KEY_UID));
       if (uidData.IsNotNull())
       {
         mitk::UIDManipulator uidManipulator(output);
         uidManipulator.SetUID(uidData->GetMetaDataObjectValue());
       }
     }
     result.push_back(output.GetPointer());
 
     MITK_INFO << "...finished!";
     return result;
   }
 
   MultiLabelSegmentationIO *MultiLabelSegmentationIO::IOClone() const { return new MultiLabelSegmentationIO(*this); }
 
   void MultiLabelSegmentationIO::InitializeDefaultMetaDataKeys()
   {
     this->m_DefaultMetaDataKeys.push_back("NRRD.space");
     this->m_DefaultMetaDataKeys.push_back("NRRD.kinds");
     this->m_DefaultMetaDataKeys.push_back(PROPERTY_NAME_TIMEGEOMETRY_TYPE);
     this->m_DefaultMetaDataKeys.push_back(PROPERTY_NAME_TIMEGEOMETRY_TIMEPOINTS);
     this->m_DefaultMetaDataKeys.push_back("ITK.InputFilterName");
     this->m_DefaultMetaDataKeys.push_back("org.mitk.multilabel.");
     this->m_DefaultMetaDataKeys.push_back("MITK.IO.");
     this->m_DefaultMetaDataKeys.push_back(MULTILABEL_SEGMENTATION_MODALITY_KEY);
   }
 
 } // namespace
diff --git a/Modules/Multilabel/mitkLabelSetImageConverter.cpp b/Modules/Multilabel/mitkLabelSetImageConverter.cpp
index b994182c38..817c0f34e7 100644
--- a/Modules/Multilabel/mitkLabelSetImageConverter.cpp
+++ b/Modules/Multilabel/mitkLabelSetImageConverter.cpp
@@ -1,198 +1,195 @@
 /*============================================================================
 
 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 <mitkITKImageImport.h>
 #include <mitkImageAccessByItk.h>
 #include <mitkImageCast.h>
 #include <mitkLabelSetImageConverter.h>
 
 #include <itkComposeImageFilter.h>
 #include <itkExtractImageFilter.h>
 #include <itkImageDuplicator.h>
 #include <itkVectorIndexSelectionCastImageFilter.h>
 
 template <typename TPixel, unsigned int VDimension>
 static void ConvertLabelSetImageToImage(const itk::Image<TPixel, VDimension> *,
                                         mitk::LabelSetImage::ConstPointer labelSetImage,
                                         mitk::Image::Pointer &image)
 {
   typedef itk::Image<TPixel, VDimension> ImageType;
   typedef itk::ComposeImageFilter<ImageType> ComposeFilterType;
   typedef itk::ImageDuplicator<ImageType> DuplicatorType;
 
   auto numberOfLayers = labelSetImage->GetNumberOfLayers();
 
   if (numberOfLayers > 1)
   {
     auto vectorImageComposer = ComposeFilterType::New();
     auto activeLayer = labelSetImage->GetActiveLayer();
 
     for (decltype(numberOfLayers) layer = 0; layer < numberOfLayers; ++layer)
     {
       auto layerImage = mitk::ImageToItkImage<TPixel, VDimension>(
         layer != activeLayer ? labelSetImage->GetLayerImage(layer) : labelSetImage);
 
       vectorImageComposer->SetInput(layer, layerImage);
     }
 
     vectorImageComposer->Update();
     // mitk::GrabItkImageMemory does not support 4D, this will handle 4D correctly
     // and create a memory managed copy
     image = mitk::ImportItkImage(vectorImageComposer->GetOutput())->Clone();
   }
   else
   {
     auto layerImage = mitk::ImageToItkImage<TPixel, VDimension>(labelSetImage);
 
     auto duplicator = DuplicatorType::New();
     duplicator->SetInputImage(layerImage);
     duplicator->Update();
 
     // mitk::GrabItkImageMemory does not support 4D, this will handle 4D correctly
     // and create a memory managed copy
     image = mitk::ImportItkImage(duplicator->GetOutput())->Clone();
   }
 }
 
 mitk::Image::Pointer mitk::ConvertLabelSetImageToImage(LabelSetImage::ConstPointer labelSetImage)
 {
   Image::Pointer image;
 
   if (labelSetImage->GetNumberOfLayers() > 0)
   {
     if (labelSetImage->GetDimension() == 4)
     {
       AccessFixedDimensionByItk_n(labelSetImage, ::ConvertLabelSetImageToImage, 4, (labelSetImage, image));
     }
     else
     {
       AccessByItk_2(labelSetImage->GetLayerImage(0), ::ConvertLabelSetImageToImage, labelSetImage, image);
     }
 
     image->SetTimeGeometry(labelSetImage->GetTimeGeometry()->Clone());
   }
 
   return image;
 }
 
 
 template <typename TPixel, unsigned int VDimensions>
 static void SplitVectorImage(const itk::VectorImage<TPixel, VDimensions>* image,
   std::vector<mitk::Image::Pointer>& result)
 {
   typedef itk::VectorImage<TPixel, VDimensions> VectorImageType;
   typedef itk::Image<TPixel, VDimensions> ImageType;
   typedef itk::VectorIndexSelectionCastImageFilter<VectorImageType, ImageType> VectorIndexSelectorType;
 
   auto numberOfLayers = image->GetVectorLength();
   for (decltype(numberOfLayers) layer = 0; layer < numberOfLayers; ++layer)
   {
     auto layerSelector = VectorIndexSelectorType::New();
     layerSelector->SetInput(image);
     layerSelector->SetIndex(layer);
     layerSelector->Update();
 
     mitk::Image::Pointer layerImage = mitk::GrabItkImageMemoryChannel(layerSelector->GetOutput(), nullptr, nullptr, false);
     result.push_back(layerImage);
   }
 }
 
 std::vector<mitk::Image::Pointer> mitk::SplitVectorImage(const Image* vecImage)
 {
   if (nullptr == vecImage)
   {
     mitkThrow() << "Invalid usage; nullptr passed to SplitVectorImage.";
   }
 
   if (vecImage->GetChannelDescriptor().GetPixelType().GetPixelType() != itk::IOPixelEnum::VECTOR)
   {
     mitkThrow() << "Invalid usage of SplitVectorImage; passed image is not a vector image. Present pixel type: "<< vecImage->GetChannelDescriptor().GetPixelType().GetPixelTypeAsString();
   }
 
   std::vector<mitk::Image::Pointer> result;
 
   if (4 == vecImage->GetDimension())
   {
     AccessVectorFixedDimensionByItk_n(vecImage, ::SplitVectorImage, 4, (result));
   }
   else
   {
     AccessVectorPixelTypeByItk_n(vecImage, ::SplitVectorImage, (result));
   }
 
   for (auto image : result)
   {
     image->SetTimeGeometry(vecImage->GetTimeGeometry()->Clone());
   }
 
   return result;
 }
 
 mitk::LabelSetImage::Pointer mitk::ConvertImageToLabelSetImage(Image::Pointer image)
 {
   std::vector<mitk::Image::Pointer> groupImages;
 
   if (image.IsNotNull())
   {
     if (image->GetChannelDescriptor().GetPixelType().GetPixelType() == itk::IOPixelEnum::VECTOR)
     {
       groupImages = SplitVectorImage(image);
     }
     else
     {
       groupImages.push_back(image);
     }
   }
   auto labelSetImage = ConvertImageVectorToLabelSetImage(groupImages, image->GetTimeGeometry());
 
   return labelSetImage;
 }
 
 mitk::LabelSetImage::Pointer mitk::ConvertImageVectorToLabelSetImage(const std::vector<mitk::Image::Pointer>& images, const mitk::TimeGeometry* timeGeometry)
 {
   LabelSetImage::Pointer labelSetImage = mitk::LabelSetImage::New();
 
   for (auto& groupImage : images)
   {
     if (groupImage== images.front())
     {
       labelSetImage->InitializeByLabeledImage(groupImage);
     }
     else
     {
       labelSetImage->AddLayer(groupImage);
     }
   }
 
   labelSetImage->SetTimeGeometry(timeGeometry->Clone());
   return labelSetImage;
 }
 
-mitk::LabelSet::Pointer mitk::GenerateLabelSetWithMappedValues(const LabelSet* sourceLabelset, std::vector<std::pair<Label::PixelType, Label::PixelType> > labelMapping)
+mitk::LabelSetImage::LabelVectorType mitk::GenerateLabelSetWithMappedValues(const LabelSetImage::ConstLabelVectorType& sourceLabelset, LabelValueMappingVector labelMapping)
 {
-  if (nullptr == sourceLabelset)
-  {
-    mitkThrow() << "Invalid usage; nullptr passed as labelset to GenerateLabelSetWithMappedValues.";
-  }
-
-  auto result = LabelSet::New();
+  LabelSetImage::LabelVectorType result;
 
-  for (auto [sourceLabelID, destLabelID] : labelMapping)
+  for (auto oldLabel : sourceLabelset)
   {
-    auto clonedLabel = sourceLabelset->GetLabel(sourceLabelID)->Clone();
-    clonedLabel->SetValue(destLabelID);
-    result->AddLabel(clonedLabel, false);
+    auto finding = std::find_if(labelMapping.begin(), labelMapping.end(), [oldLabel](const std::pair<Label::PixelType, Label::PixelType>& mapping) {return oldLabel->GetValue() == mapping.first; });
+    if (finding != labelMapping.end())
+    {
+      auto clonedLabel = oldLabel->Clone();
+      clonedLabel->SetValue(finding->second);
+      result.push_back(clonedLabel);
+    }
   }
-  result->SetLayer(sourceLabelset->GetLayer());
-
   return result;
 }
diff --git a/Modules/Multilabel/mitkLabelSetImageConverter.h b/Modules/Multilabel/mitkLabelSetImageConverter.h
index 1e1b577d79..09121dd627 100644
--- a/Modules/Multilabel/mitkLabelSetImageConverter.h
+++ b/Modules/Multilabel/mitkLabelSetImageConverter.h
@@ -1,40 +1,40 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef mitkLabelSetImageConverter_h
 #define mitkLabelSetImageConverter_h
 
 #include <mitkLabelSetImage.h>
 
 namespace mitk
 {
   /**
    * \brief Convert mitk::LabelSetImage to mitk::Image (itk::VectorImage)
    */
   MITKMULTILABEL_EXPORT Image::Pointer ConvertLabelSetImageToImage(LabelSetImage::ConstPointer labelSetImage);
 
   /**
    * \brief Convert mitk::Image to mitk::LabelSetImage, templating and differentation between itk::Image and
    * itk::VectorImage is internal
    */
   MITKMULTILABEL_EXPORT LabelSetImage::Pointer ConvertImageToLabelSetImage(Image::Pointer image);
   MITKMULTILABEL_EXPORT LabelSetImage::Pointer ConvertImageVectorToLabelSetImage(const std::vector<mitk::Image::Pointer>& images, const TimeGeometry* timeGeometry);
 
   MITKMULTILABEL_EXPORT std::vector<mitk::Image::Pointer> SplitVectorImage(const Image* vecImage);
 
-  /** Function takes a label set and transfers all labels indicated in the label mapping (first element of pair) into a result label set. In the result label set
-  the cloned labels will have the label value indicated by the mapping (second element of pair).
+  /** Function takes a vector of labels and transfers all labels as clones with adapted label values to the result vector.
+  The values will be adapted according to the provided mapping (key is the old value, value the new).
   @remark: Only labels will be transfered, nothing else. So things like message observers or m_ReservedLabelValuesFunctor must be copied explicitly.*/
-  MITKMULTILABEL_EXPORT LabelSet::Pointer GenerateLabelSetWithMappedValues(const LabelSet* sourceLabelset, std::vector<std::pair<Label::PixelType, Label::PixelType> > labelMapping);
+  MITKMULTILABEL_EXPORT LabelSetImage::LabelVectorType GenerateLabelSetWithMappedValues(const LabelSetImage::ConstLabelVectorType&, LabelValueMappingVector labelMapping);
 }
 
 #endif
diff --git a/Modules/Multilabel/mitkLabelSetImageSurfaceStampFilter.cpp b/Modules/Multilabel/mitkLabelSetImageSurfaceStampFilter.cpp
index d0388bf099..b99b1f928c 100644
--- a/Modules/Multilabel/mitkLabelSetImageSurfaceStampFilter.cpp
+++ b/Modules/Multilabel/mitkLabelSetImageSurfaceStampFilter.cpp
@@ -1,108 +1,108 @@
 /*============================================================================
 
 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 "mitkLabelSetImageSurfaceStampFilter.h"
 
 #include "mitkImageAccessByItk.h"
 #include "mitkImageCast.h"
 
 #include <mitkLabelSetImage.h>
 #include <mitkLabelSetImage.h>
 #include <mitkSurface.h>
 #include <mitkSurfaceToImageFilter.h>
 
 mitk::LabelSetImageSurfaceStampFilter::LabelSetImageSurfaceStampFilter() : m_ForceOverwrite(false)
 {
   this->SetNumberOfIndexedInputs(1);
   this->SetNumberOfRequiredInputs(1);
 }
 
 mitk::LabelSetImageSurfaceStampFilter::~LabelSetImageSurfaceStampFilter()
 {
 }
 
 void mitk::LabelSetImageSurfaceStampFilter::GenerateData()
 {
   // GenerateOutputInformation();
   this->SetNthOutput(0, this->GetInput(0));
 
   mitk::Image::Pointer inputImage = this->GetInput(0);
 
   if (m_Surface.IsNull())
   {
     MITK_ERROR << "Input surface is nullptr.";
     return;
   }
 
   mitk::SurfaceToImageFilter::Pointer surfaceToImageFilter = mitk::SurfaceToImageFilter::New();
   surfaceToImageFilter->MakeOutputBinaryOn();
   surfaceToImageFilter->SetInput(m_Surface);
   surfaceToImageFilter->SetImage(inputImage);
   surfaceToImageFilter->Update();
   mitk::Image::Pointer resultImage = surfaceToImageFilter->GetOutput();
 
   AccessByItk_1(inputImage, ItkImageProcessing, resultImage);
   inputImage->DisconnectPipeline();
 }
 
 template <typename TPixel, unsigned int VImageDimension>
 void mitk::LabelSetImageSurfaceStampFilter::ItkImageProcessing(itk::Image<TPixel, VImageDimension> *itkImage,
                                                                mitk::Image::Pointer resultImage)
 {
   typedef itk::Image<TPixel, VImageDimension> ImageType;
   mitk::LabelSetImage::Pointer LabelSetInputImage = dynamic_cast<LabelSetImage *>(GetInput());
   try
   {
     typename ImageType::Pointer itkResultImage = ImageType::New();
     mitk::CastToItkImage(resultImage, itkResultImage);
 
     typedef itk::ImageRegionConstIterator<ImageType> SourceIteratorType;
     typedef itk::ImageRegionIterator<ImageType> TargetIteratorType;
 
     SourceIteratorType sourceIter(itkResultImage, itkResultImage->GetLargestPossibleRegion());
     sourceIter.GoToBegin();
 
     TargetIteratorType targetIter(itkImage, itkImage->GetLargestPossibleRegion());
     targetIter.GoToBegin();
 
-    int activeLabel = (LabelSetInputImage->GetActiveLabel(LabelSetInputImage->GetActiveLayer()))->GetValue();
+    int activeLabel = LabelSetInputImage->GetActiveLabel()->GetValue();
 
     while (!sourceIter.IsAtEnd())
     {
       auto sourceValue = static_cast<int>(sourceIter.Get());
       auto targetValue = static_cast<int>(targetIter.Get());
 
       if ((sourceValue != LabelSetImage::UnlabeledValue) &&
           (m_ForceOverwrite ||
            !LabelSetInputImage->GetLabel(targetValue)->GetLocked())) // skip unlabled pixels and locked labels
       {
         targetIter.Set(activeLabel);
       }
       ++sourceIter;
       ++targetIter;
     }
   }
   catch (itk::ExceptionObject &e)
   {
     mitkThrow() << e.GetDescription();
   }
   this->Modified();
 }
 
 void mitk::LabelSetImageSurfaceStampFilter::GenerateOutputInformation()
 {
   mitk::Image::Pointer inputImage = (mitk::Image *)this->GetInput();
   mitk::Image::Pointer output = this->GetOutput();
   itkDebugMacro(<< "GenerateOutputInformation()");
   if (inputImage.IsNull())
     return;
 }
diff --git a/Modules/Multilabel/mitkLabelSetImageToSurfaceThreadedFilter.cpp b/Modules/Multilabel/mitkLabelSetImageToSurfaceThreadedFilter.cpp
index e70aa8ecd7..ae1caca213 100644
--- a/Modules/Multilabel/mitkLabelSetImageToSurfaceThreadedFilter.cpp
+++ b/Modules/Multilabel/mitkLabelSetImageToSurfaceThreadedFilter.cpp
@@ -1,130 +1,130 @@
 /*============================================================================
 
 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 "mitkLabelSetImageToSurfaceThreadedFilter.h"
 
 #include "mitkLabelSetImage.h"
 #include "mitkLabelSetImageToSurfaceFilter.h"
 
 namespace mitk
 {
   LabelSetImageToSurfaceThreadedFilter::LabelSetImageToSurfaceThreadedFilter() : m_RequestedLabel(1), m_Result(nullptr)
   {
   }
 
   LabelSetImageToSurfaceThreadedFilter::~LabelSetImageToSurfaceThreadedFilter() {}
   void LabelSetImageToSurfaceThreadedFilter::Initialize(const NonBlockingAlgorithm *other)
   {
     Superclass::Initialize(other);
   }
 
   bool LabelSetImageToSurfaceThreadedFilter::ReadyToRun()
   {
     Image::Pointer image;
     GetPointerParameter("Input", image);
 
     return image.IsNotNull() && GetGroupNode();
   }
 
   bool LabelSetImageToSurfaceThreadedFilter::ThreadedUpdateFunction()
   {
     LabelSetImage::Pointer image;
     this->GetPointerParameter("Input", image);
 
     //  ProcessObserver::Pointer obsv;
     /*
       try
       {
         this->GetPointerParameter("Observer", obsv);
       }
       catch (std::invalid_argument&)
       {
     //    MITK_WARN << "None observer provided.";
       }
     */
     bool useSmoothing(false);
     try
     {
       this->GetParameter("Smooth", useSmoothing);
     }
     catch (std::invalid_argument &)
     {
       MITK_WARN << "\"Smooth\" parameter was not set: will use the default value (" << useSmoothing << ").";
     }
 
     try
     {
       this->GetParameter("RequestedLabel", m_RequestedLabel);
     }
     catch (std::invalid_argument &)
     {
       MITK_WARN << "\"RequestedLabel\" parameter was not set: will use the default value (" << m_RequestedLabel << ").";
     }
 
     mitk::LabelSetImageToSurfaceFilter::Pointer filter = mitk::LabelSetImageToSurfaceFilter::New();
     filter->SetInput(image);
     //  filter->SetObserver(obsv);
     filter->SetGenerateAllLabels(false);
     filter->SetRequestedLabel(m_RequestedLabel);
     filter->SetUseSmoothing(useSmoothing);
 
     try
     {
       filter->Update();
     }
     catch (itk::ExceptionObject &e)
     {
       MITK_ERROR << "Exception caught: " << e.GetDescription();
       return false;
     }
     catch (std::exception &e)
     {
       MITK_ERROR << "Exception caught: " << e.what();
       return false;
     }
     catch (...)
     {
       MITK_ERROR << "Unknown exception caught";
       return false;
     }
 
     m_Result = filter->GetOutput();
 
     if (m_Result.IsNull() || !m_Result->GetVtkPolyData())
       return false;
 
     m_Result->DisconnectPipeline();
 
     return true;
   }
 
   void LabelSetImageToSurfaceThreadedFilter::ThreadedUpdateSuccessful()
   {
     LabelSetImage::Pointer image;
     this->GetPointerParameter("Input", image);
 
     std::string name = this->GetGroupNode()->GetName();
     name.append("-surf");
 
     mitk::DataNode::Pointer node = mitk::DataNode::New();
     node->SetData(m_Result);
     node->SetName(name);
 
-    mitk::Color color = image->GetLabel(m_RequestedLabel, image->GetActiveLayer())->GetColor();
+    mitk::Color color = image->GetLabel(m_RequestedLabel)->GetColor();
     node->SetColor(color);
 
     this->InsertBelowGroupNode(node);
 
     Superclass::ThreadedUpdateSuccessful();
   }
 
 } // namespace
diff --git a/Modules/Multilabel/mitkLabelSetImageVtkMapper2D.cpp b/Modules/Multilabel/mitkLabelSetImageVtkMapper2D.cpp
index 9436894b13..f0bbb2e98e 100644
--- a/Modules/Multilabel/mitkLabelSetImageVtkMapper2D.cpp
+++ b/Modules/Multilabel/mitkLabelSetImageVtkMapper2D.cpp
@@ -1,649 +1,649 @@
 /*============================================================================
 
 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 "mitkLabelSetImageVtkMapper2D.h"
 
 // MITK
 #include <mitkAbstractTransformGeometry.h>
 #include <mitkDataNode.h>
 #include <mitkImageSliceSelector.h>
 #include <mitkImageStatisticsHolder.h>
 #include <mitkLevelWindowProperty.h>
 #include <mitkLookupTableProperty.h>
 #include <mitkPixelType.h>
 #include <mitkPlaneClipping.h>
 #include <mitkPlaneGeometry.h>
 #include <mitkProperties.h>
 #include <mitkResliceMethodProperty.h>
 #include <mitkTransferFunctionProperty.h>
 #include <mitkVtkResliceInterpolationProperty.h>
 
 // MITK Rendering
 #include "vtkMitkLevelWindowFilter.h"
 #include "vtkMitkThickSlicesFilter.h"
 #include "vtkNeverTranslucentTexture.h"
 
 // VTK
 #include <vtkCamera.h>
 #include <vtkCellArray.h>
 #include <vtkImageData.h>
 #include <vtkImageReslice.h>
 #include <vtkLookupTable.h>
 #include <vtkMatrix4x4.h>
 #include <vtkPlaneSource.h>
 #include <vtkPoints.h>
 #include <vtkPolyData.h>
 #include <vtkPolyDataMapper.h>
 #include <vtkProperty.h>
 #include <vtkTransform.h>
 //#include <vtkOpenGLTexture.h>
 
 // ITK
 #include <itkRGBAPixel.h>
 #include <mitkRenderingModeProperty.h>
 
 mitk::LabelSetImageVtkMapper2D::LabelSetImageVtkMapper2D()
 {
 }
 
 mitk::LabelSetImageVtkMapper2D::~LabelSetImageVtkMapper2D()
 {
 }
 
 vtkProp *mitk::LabelSetImageVtkMapper2D::GetVtkProp(mitk::BaseRenderer *renderer)
 {
   // return the actor corresponding to the renderer
   return m_LSH.GetLocalStorage(renderer)->m_Actors;
 }
 
 mitk::LabelSetImageVtkMapper2D::LocalStorage *mitk::LabelSetImageVtkMapper2D::GetLocalStorage(
   mitk::BaseRenderer *renderer)
 {
   return m_LSH.GetLocalStorage(renderer);
 }
 
 void mitk::LabelSetImageVtkMapper2D::GenerateDataForRenderer(mitk::BaseRenderer *renderer)
 {
   LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer);
   mitk::DataNode *node = this->GetDataNode();
   auto *image = dynamic_cast<mitk::LabelSetImage *>(node->GetData());
   assert(image && image->IsInitialized());
 
   // check if there is a valid worldGeometry
   const PlaneGeometry *worldGeometry = renderer->GetCurrentWorldPlaneGeometry();
   if ((worldGeometry == nullptr) || (!worldGeometry->IsValid()) || (!worldGeometry->HasReferenceGeometry()))
     return;
 
   image->Update();
 
   int numberOfLayers = image->GetNumberOfLayers();
   int activeLayer = image->GetActiveLayer();
 
   float opacity = 1.0f;
   node->GetOpacity(opacity, renderer, "opacity");
 
   if (numberOfLayers != localStorage->m_NumberOfLayers)
   {
     localStorage->m_NumberOfLayers = numberOfLayers;
     localStorage->m_ReslicedImageVector.clear();
     localStorage->m_ReslicerVector.clear();
     localStorage->m_LayerTextureVector.clear();
     localStorage->m_LevelWindowFilterVector.clear();
     localStorage->m_LayerMapperVector.clear();
     localStorage->m_LayerActorVector.clear();
 
     localStorage->m_Actors = vtkSmartPointer<vtkPropAssembly>::New();
 
     for (int lidx = 0; lidx < numberOfLayers; ++lidx)
     {
       localStorage->m_ReslicedImageVector.push_back(vtkSmartPointer<vtkImageData>::New());
       localStorage->m_ReslicerVector.push_back(mitk::ExtractSliceFilter::New());
       localStorage->m_LayerTextureVector.push_back(vtkSmartPointer<vtkNeverTranslucentTexture>::New());
       localStorage->m_LevelWindowFilterVector.push_back(vtkSmartPointer<vtkMitkLevelWindowFilter>::New());
       localStorage->m_LayerMapperVector.push_back(vtkSmartPointer<vtkPolyDataMapper>::New());
       localStorage->m_LayerActorVector.push_back(vtkSmartPointer<vtkActor>::New());
 
       // do not repeat the texture (the image)
       localStorage->m_LayerTextureVector[lidx]->RepeatOff();
 
       // set corresponding mappers for the actors
       localStorage->m_LayerActorVector[lidx]->SetMapper(localStorage->m_LayerMapperVector[lidx]);
 
       localStorage->m_Actors->AddPart(localStorage->m_LayerActorVector[lidx]);
     }
 
     localStorage->m_Actors->AddPart(localStorage->m_OutlineShadowActor);
     localStorage->m_Actors->AddPart(localStorage->m_OutlineActor);
   }
 
   // early out if there is no intersection of the current rendering geometry
   // and the geometry of the image that is to be rendered.
   if (!RenderingGeometryIntersectsImage(worldGeometry, image->GetSlicedGeometry()))
   {
     // set image to nullptr, to clear the texture in 3D, because
     // the latest image is used there if the plane is out of the geometry
     // see bug-13275
     for (int lidx = 0; lidx < numberOfLayers; ++lidx)
     {
       localStorage->m_ReslicedImageVector[lidx] = nullptr;
       localStorage->m_LayerMapperVector[lidx]->SetInputData(localStorage->m_EmptyPolyData);
       localStorage->m_OutlineActor->SetVisibility(false);
       localStorage->m_OutlineShadowActor->SetVisibility(false);
     }
     return;
   }
 
   for (int lidx = 0; lidx < numberOfLayers; ++lidx)
   {
     mitk::Image *layerImage = nullptr;
 
     // set main input for ExtractSliceFilter
     if (lidx == activeLayer)
       layerImage = image;
     else
       layerImage = image->GetLayerImage(lidx);
 
     localStorage->m_ReslicerVector[lidx]->SetInput(layerImage);
     localStorage->m_ReslicerVector[lidx]->SetWorldGeometry(worldGeometry);
     localStorage->m_ReslicerVector[lidx]->SetTimeStep(this->GetTimestep());
 
     // set the transformation of the image to adapt reslice axis
     localStorage->m_ReslicerVector[lidx]->SetResliceTransformByGeometry(
       layerImage->GetTimeGeometry()->GetGeometryForTimeStep(this->GetTimestep()));
 
     // is the geometry of the slice based on the image image or the worldgeometry?
     bool inPlaneResampleExtentByGeometry = false;
     node->GetBoolProperty("in plane resample extent by geometry", inPlaneResampleExtentByGeometry, renderer);
     localStorage->m_ReslicerVector[lidx]->SetInPlaneResampleExtentByGeometry(inPlaneResampleExtentByGeometry);
     localStorage->m_ReslicerVector[lidx]->SetInterpolationMode(ExtractSliceFilter::RESLICE_NEAREST);
     localStorage->m_ReslicerVector[lidx]->SetVtkOutputRequest(true);
 
     // this is needed when thick mode was enabled before. These variables have to be reset to default values
     localStorage->m_ReslicerVector[lidx]->SetOutputDimensionality(2);
     localStorage->m_ReslicerVector[lidx]->SetOutputSpacingZDirection(1.0);
     localStorage->m_ReslicerVector[lidx]->SetOutputExtentZDirection(0, 0);
 
     // Bounds information for reslicing (only required if reference geometry is present)
     // this used for generating a vtkPLaneSource with the right size
     double sliceBounds[6];
     sliceBounds[0] = 0.0;
     sliceBounds[1] = 0.0;
     sliceBounds[2] = 0.0;
     sliceBounds[3] = 0.0;
     sliceBounds[4] = 0.0;
     sliceBounds[5] = 0.0;
 
     localStorage->m_ReslicerVector[lidx]->GetClippedPlaneBounds(sliceBounds);
 
     // setup the textured plane
     this->GeneratePlane(renderer, sliceBounds);
 
     // get the spacing of the slice
     localStorage->m_mmPerPixel = localStorage->m_ReslicerVector[lidx]->GetOutputSpacing();
     localStorage->m_ReslicerVector[lidx]->Modified();
     // start the pipeline with updating the largest possible, needed if the geometry of the image has changed
     localStorage->m_ReslicerVector[lidx]->UpdateLargestPossibleRegion();
     localStorage->m_ReslicedImageVector[lidx] = localStorage->m_ReslicerVector[lidx]->GetVtkOutput();
 
     const auto *planeGeometry = dynamic_cast<const PlaneGeometry *>(worldGeometry);
 
     double textureClippingBounds[6];
     for (auto &textureClippingBound : textureClippingBounds)
     {
       textureClippingBound = 0.0;
     }
 
     // Calculate the actual bounds of the transformed plane clipped by the
     // dataset bounding box; this is required for drawing the texture at the
     // correct position during 3D mapping.
     mitk::PlaneClipping::CalculateClippedPlaneBounds(layerImage->GetGeometry(), planeGeometry, textureClippingBounds);
 
     textureClippingBounds[0] = static_cast<int>(textureClippingBounds[0] / localStorage->m_mmPerPixel[0] + 0.5);
     textureClippingBounds[1] = static_cast<int>(textureClippingBounds[1] / localStorage->m_mmPerPixel[0] + 0.5);
     textureClippingBounds[2] = static_cast<int>(textureClippingBounds[2] / localStorage->m_mmPerPixel[1] + 0.5);
     textureClippingBounds[3] = static_cast<int>(textureClippingBounds[3] / localStorage->m_mmPerPixel[1] + 0.5);
 
     // clipping bounds for cutting the imageLayer
     localStorage->m_LevelWindowFilterVector[lidx]->SetClippingBounds(textureClippingBounds);
 
     localStorage->m_LevelWindowFilterVector[lidx]->SetLookupTable(
-      image->GetLabelSet(lidx)->GetLookupTable()->GetVtkLookupTable());
+      image->GetLookupTable()->GetVtkLookupTable());
 
     // do not use a VTK lookup table (we do that ourselves in m_LevelWindowFilter)
     localStorage->m_LayerTextureVector[lidx]->SetColorModeToDirectScalars();
 
     // connect the imageLayer with the levelwindow filter
     localStorage->m_LevelWindowFilterVector[lidx]->SetInputData(localStorage->m_ReslicedImageVector[lidx]);
     // connect the texture with the output of the levelwindow filter
 
     // check for texture interpolation property
     bool textureInterpolation = false;
     node->GetBoolProperty("texture interpolation", textureInterpolation, renderer);
 
     // set the interpolation modus according to the property
     localStorage->m_LayerTextureVector[lidx]->SetInterpolate(textureInterpolation);
 
     localStorage->m_LayerTextureVector[lidx]->SetInputConnection(
       localStorage->m_LevelWindowFilterVector[lidx]->GetOutputPort());
 
     this->TransformActor(renderer);
 
     // set the plane as input for the mapper
     localStorage->m_LayerMapperVector[lidx]->SetInputConnection(localStorage->m_Plane->GetOutputPort());
 
     // set the texture for the actor
     localStorage->m_LayerActorVector[lidx]->SetTexture(localStorage->m_LayerTextureVector[lidx]);
     localStorage->m_LayerActorVector[lidx]->GetProperty()->SetOpacity(opacity);
   }
 
-  mitk::Label* activeLabel = image->GetActiveLabel(activeLayer);
+  mitk::Label* activeLabel = image->GetActiveLabel();
   if (nullptr != activeLabel)
   {
     bool contourActive = false;
     node->GetBoolProperty("labelset.contour.active", contourActive, renderer);
     if (contourActive && activeLabel->GetVisible()) //contour rendering
     {
       //generate contours/outlines
       localStorage->m_OutlinePolyData =
         this->CreateOutlinePolyData(renderer, localStorage->m_ReslicedImageVector[activeLayer], activeLabel->GetValue());
       localStorage->m_OutlineActor->SetVisibility(true);
       localStorage->m_OutlineShadowActor->SetVisibility(true);
       const mitk::Color& color = activeLabel->GetColor();
       localStorage->m_OutlineActor->GetProperty()->SetColor(color.GetRed(), color.GetGreen(), color.GetBlue());
       localStorage->m_OutlineShadowActor->GetProperty()->SetColor(0, 0, 0);
 
       float contourWidth(2.0);
       node->GetFloatProperty("labelset.contour.width", contourWidth, renderer);
       localStorage->m_OutlineActor->GetProperty()->SetLineWidth(contourWidth);
       localStorage->m_OutlineShadowActor->GetProperty()->SetLineWidth(contourWidth * 1.5);
 
       localStorage->m_OutlineActor->GetProperty()->SetOpacity(opacity);
       localStorage->m_OutlineShadowActor->GetProperty()->SetOpacity(opacity);
 
       localStorage->m_OutlineMapper->SetInputData(localStorage->m_OutlinePolyData);
       return;
     }
   }
   localStorage->m_OutlineActor->SetVisibility(false);
   localStorage->m_OutlineShadowActor->SetVisibility(false);
 }
 
 bool mitk::LabelSetImageVtkMapper2D::RenderingGeometryIntersectsImage(const PlaneGeometry *renderingGeometry,
                                                                       SlicedGeometry3D *imageGeometry)
 {
   // if either one of the two geometries is nullptr we return true
   // for safety reasons
   if (renderingGeometry == nullptr || imageGeometry == nullptr)
     return true;
 
   // get the distance for the first cornerpoint
   ScalarType initialDistance = renderingGeometry->SignedDistance(imageGeometry->GetCornerPoint(0));
   for (int i = 1; i < 8; i++)
   {
     mitk::Point3D cornerPoint = imageGeometry->GetCornerPoint(i);
 
     // get the distance to the other cornerpoints
     ScalarType distance = renderingGeometry->SignedDistance(cornerPoint);
 
     // if it has not the same signing as the distance of the first point
     if (initialDistance * distance < 0)
     {
       // we have an intersection and return true
       return true;
     }
   }
 
   // all distances have the same sign, no intersection and we return false
   return false;
 }
 
 vtkSmartPointer<vtkPolyData> mitk::LabelSetImageVtkMapper2D::CreateOutlinePolyData(mitk::BaseRenderer *renderer,
                                                                                    vtkImageData *image,
                                                                                    int pixelValue)
 {
   LocalStorage *localStorage = this->GetLocalStorage(renderer);
 
   // get the min and max index values of each direction
   int *extent = image->GetExtent();
   int xMin = extent[0];
   int xMax = extent[1];
   int yMin = extent[2];
   int yMax = extent[3];
 
   int *dims = image->GetDimensions(); // dimensions of the image
   int line = dims[0];                 // how many pixels per line?
   int x = xMin;                       // pixel index x
   int y = yMin;                       // pixel index y
 
   // get the depth for each contour
   float depth = this->CalculateLayerDepth(renderer);
 
   vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();      // the points to draw
   vtkSmartPointer<vtkCellArray> lines = vtkSmartPointer<vtkCellArray>::New(); // the lines to connect the points
 
   // We take the pointer to the first pixel of the image
   auto *currentPixel = static_cast<mitk::Label::PixelType *>(image->GetScalarPointer());
 
   while (y <= yMax)
   {
     // if the current pixel value is set to something
     if ((currentPixel) && (*currentPixel == pixelValue))
     {
       // check in which direction a line is necessary
       // a line is added if the neighbor of the current pixel has the value 0
       // and if the pixel is located at the edge of the image
 
       // if   vvvvv  not the first line vvvvv
       if (y > yMin && *(currentPixel - line) != pixelValue)
       { // x direction - bottom edge of the pixel
         // add the 2 points
         vtkIdType p1 =
           points->InsertNextPoint(x * localStorage->m_mmPerPixel[0], y * localStorage->m_mmPerPixel[1], depth);
         vtkIdType p2 =
           points->InsertNextPoint((x + 1) * localStorage->m_mmPerPixel[0], y * localStorage->m_mmPerPixel[1], depth);
         // add the line between both points
         lines->InsertNextCell(2);
         lines->InsertCellPoint(p1);
         lines->InsertCellPoint(p2);
       }
 
       // if   vvvvv  not the last line vvvvv
       if (y < yMax && *(currentPixel + line) != pixelValue)
       { // x direction - top edge of the pixel
         vtkIdType p1 =
           points->InsertNextPoint(x * localStorage->m_mmPerPixel[0], (y + 1) * localStorage->m_mmPerPixel[1], depth);
         vtkIdType p2 = points->InsertNextPoint(
           (x + 1) * localStorage->m_mmPerPixel[0], (y + 1) * localStorage->m_mmPerPixel[1], depth);
         lines->InsertNextCell(2);
         lines->InsertCellPoint(p1);
         lines->InsertCellPoint(p2);
       }
 
       // if   vvvvv  not the first pixel vvvvv
       if ((x > xMin || y > yMin) && *(currentPixel - 1) != pixelValue)
       { // y direction - left edge of the pixel
         vtkIdType p1 =
           points->InsertNextPoint(x * localStorage->m_mmPerPixel[0], y * localStorage->m_mmPerPixel[1], depth);
         vtkIdType p2 =
           points->InsertNextPoint(x * localStorage->m_mmPerPixel[0], (y + 1) * localStorage->m_mmPerPixel[1], depth);
         lines->InsertNextCell(2);
         lines->InsertCellPoint(p1);
         lines->InsertCellPoint(p2);
       }
 
       // if   vvvvv  not the last pixel vvvvv
       if ((y < yMax || (x < xMax)) && *(currentPixel + 1) != pixelValue)
       { // y direction - right edge of the pixel
         vtkIdType p1 =
           points->InsertNextPoint((x + 1) * localStorage->m_mmPerPixel[0], y * localStorage->m_mmPerPixel[1], depth);
         vtkIdType p2 = points->InsertNextPoint(
           (x + 1) * localStorage->m_mmPerPixel[0], (y + 1) * localStorage->m_mmPerPixel[1], depth);
         lines->InsertNextCell(2);
         lines->InsertCellPoint(p1);
         lines->InsertCellPoint(p2);
       }
 
       /*  now consider pixels at the edge of the image  */
 
       // if   vvvvv  left edge of image vvvvv
       if (x == xMin)
       { // draw left edge of the pixel
         vtkIdType p1 =
           points->InsertNextPoint(x * localStorage->m_mmPerPixel[0], y * localStorage->m_mmPerPixel[1], depth);
         vtkIdType p2 =
           points->InsertNextPoint(x * localStorage->m_mmPerPixel[0], (y + 1) * localStorage->m_mmPerPixel[1], depth);
         lines->InsertNextCell(2);
         lines->InsertCellPoint(p1);
         lines->InsertCellPoint(p2);
       }
 
       // if   vvvvv  right edge of image vvvvv
       if (x == xMax)
       { // draw right edge of the pixel
         vtkIdType p1 =
           points->InsertNextPoint((x + 1) * localStorage->m_mmPerPixel[0], y * localStorage->m_mmPerPixel[1], depth);
         vtkIdType p2 = points->InsertNextPoint(
           (x + 1) * localStorage->m_mmPerPixel[0], (y + 1) * localStorage->m_mmPerPixel[1], depth);
         lines->InsertNextCell(2);
         lines->InsertCellPoint(p1);
         lines->InsertCellPoint(p2);
       }
 
       // if   vvvvv  bottom edge of image vvvvv
       if (y == yMin)
       { // draw bottom edge of the pixel
         vtkIdType p1 =
           points->InsertNextPoint(x * localStorage->m_mmPerPixel[0], y * localStorage->m_mmPerPixel[1], depth);
         vtkIdType p2 =
           points->InsertNextPoint((x + 1) * localStorage->m_mmPerPixel[0], y * localStorage->m_mmPerPixel[1], depth);
         lines->InsertNextCell(2);
         lines->InsertCellPoint(p1);
         lines->InsertCellPoint(p2);
       }
 
       // if   vvvvv  top edge of image vvvvv
       if (y == yMax)
       { // draw top edge of the pixel
         vtkIdType p1 =
           points->InsertNextPoint(x * localStorage->m_mmPerPixel[0], (y + 1) * localStorage->m_mmPerPixel[1], depth);
         vtkIdType p2 = points->InsertNextPoint(
           (x + 1) * localStorage->m_mmPerPixel[0], (y + 1) * localStorage->m_mmPerPixel[1], depth);
         lines->InsertNextCell(2);
         lines->InsertCellPoint(p1);
         lines->InsertCellPoint(p2);
       }
     } // end if currentpixel is set
 
     x++;
 
     if (x > xMax)
     { // reached end of line
       x = xMin;
       y++;
     }
 
     // Increase the pointer-position to the next pixel.
     // This is safe, as the while-loop and the x-reset logic above makes
     // sure we do not exceed the bounds of the image
     currentPixel++;
   } // end of while
 
   // Create a polydata to store everything in
   vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();
   // Add the points to the dataset
   polyData->SetPoints(points);
   // Add the lines to the dataset
   polyData->SetLines(lines);
   return polyData;
 }
 
 void mitk::LabelSetImageVtkMapper2D::ApplyColor(mitk::BaseRenderer *renderer, const mitk::Color &color)
 {
   LocalStorage *localStorage = this->GetLocalStorage(renderer);
   localStorage->m_OutlineActor->GetProperty()->SetColor(color.GetRed(), color.GetGreen(), color.GetBlue());
   localStorage->m_OutlineShadowActor->GetProperty()->SetColor(0, 0, 0);
 }
 
 void mitk::LabelSetImageVtkMapper2D::ApplyOpacity(mitk::BaseRenderer *renderer, int layer)
 {
   LocalStorage *localStorage = this->GetLocalStorage(renderer);
   float opacity = 1.0f;
   this->GetDataNode()->GetOpacity(opacity, renderer, "opacity");
   localStorage->m_LayerActorVector[layer]->GetProperty()->SetOpacity(opacity);
   localStorage->m_OutlineActor->GetProperty()->SetOpacity(opacity);
   localStorage->m_OutlineShadowActor->GetProperty()->SetOpacity(opacity);
 }
 
 void mitk::LabelSetImageVtkMapper2D::ApplyLookuptable(mitk::BaseRenderer *renderer, int layer)
 {
   LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer);
   auto *input = dynamic_cast<mitk::LabelSetImage *>(this->GetDataNode()->GetData());
   localStorage->m_LevelWindowFilterVector[layer]->SetLookupTable(
-    input->GetLabelSet(layer)->GetLookupTable()->GetVtkLookupTable());
+    input->GetLookupTable()->GetVtkLookupTable());
 }
 
 void mitk::LabelSetImageVtkMapper2D::Update(mitk::BaseRenderer *renderer)
 {
   bool visible = true;
   const DataNode *node = this->GetDataNode();
   node->GetVisibility(visible, renderer, "visible");
 
   if (!visible)
     return;
 
   auto *image = dynamic_cast<mitk::LabelSetImage *>(node->GetData());
 
   if (image == nullptr || image->IsInitialized() == false)
     return;
 
   // Calculate time step of the image data for the specified renderer (integer value)
   this->CalculateTimeStep(renderer);
 
   // Check if time step is valid
   const TimeGeometry *dataTimeGeometry = image->GetTimeGeometry();
   if ((dataTimeGeometry == nullptr) || (dataTimeGeometry->CountTimeSteps() == 0) ||
       (!dataTimeGeometry->IsValidTimeStep(this->GetTimestep())))
   {
     return;
   }
 
   image->UpdateOutputInformation();
   LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer);
 
   // check if something important has changed and we need to re-render
 
   if ((localStorage->m_LastDataUpdateTime < image->GetMTime()) ||
       (localStorage->m_LastDataUpdateTime < image->GetPipelineMTime()) ||
       (localStorage->m_LastDataUpdateTime < renderer->GetCurrentWorldPlaneGeometryUpdateTime()) ||
       (localStorage->m_LastDataUpdateTime < renderer->GetCurrentWorldPlaneGeometry()->GetMTime()))
   {
     this->GenerateDataForRenderer(renderer);
     localStorage->m_LastDataUpdateTime.Modified();
   }
   else if ((localStorage->m_LastPropertyUpdateTime < node->GetPropertyList()->GetMTime()) ||
            (localStorage->m_LastPropertyUpdateTime < node->GetPropertyList(renderer)->GetMTime()) ||
            (localStorage->m_LastPropertyUpdateTime < image->GetPropertyList()->GetMTime()))
   {
     this->GenerateDataForRenderer(renderer);
     localStorage->m_LastPropertyUpdateTime.Modified();
   }
 }
 
 // set the two points defining the textured plane according to the dimension and spacing
 void mitk::LabelSetImageVtkMapper2D::GeneratePlane(mitk::BaseRenderer *renderer, double planeBounds[6])
 {
   LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer);
 
   float depth = this->CalculateLayerDepth(renderer);
   // Set the origin to (xMin; yMin; depth) of the plane. This is necessary for obtaining the correct
   // plane size in crosshair rotation and swivel mode.
   localStorage->m_Plane->SetOrigin(planeBounds[0], planeBounds[2], depth);
   // These two points define the axes of the plane in combination with the origin.
   // Point 1 is the x-axis and point 2 the y-axis.
   // Each plane is transformed according to the view (axial, coronal and sagittal) afterwards.
   localStorage->m_Plane->SetPoint1(planeBounds[1], planeBounds[2], depth); // P1: (xMax, yMin, depth)
   localStorage->m_Plane->SetPoint2(planeBounds[0], planeBounds[3], depth); // P2: (xMin, yMax, depth)
 }
 
 float mitk::LabelSetImageVtkMapper2D::CalculateLayerDepth(mitk::BaseRenderer *renderer)
 {
   // get the clipping range to check how deep into z direction we can render images
   double maxRange = renderer->GetVtkRenderer()->GetActiveCamera()->GetClippingRange()[1];
 
   // Due to a VTK bug, we cannot use the whole clipping range. /100 is empirically determined
   float depth = -maxRange * 0.01; // divide by 100
   int layer = 0;
   GetDataNode()->GetIntProperty("layer", layer, renderer);
   // add the layer property for each image to render images with a higher layer on top of the others
   depth += layer * 10; //*10: keep some room for each image (e.g. for ODFs in between)
   if (depth > 0.0f)
   {
     depth = 0.0f;
     MITK_WARN << "Layer value exceeds clipping range. Set to minimum instead.";
   }
   return depth;
 }
 
 void mitk::LabelSetImageVtkMapper2D::TransformActor(mitk::BaseRenderer *renderer)
 {
   LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer);
   // get the transformation matrix of the reslicer in order to render the slice as axial, coronal or sagittal
   vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
   vtkSmartPointer<vtkMatrix4x4> matrix = localStorage->m_ReslicerVector[0]->GetResliceAxes(); // same for all layers
   trans->SetMatrix(matrix);
 
   for (int lidx = 0; lidx < localStorage->m_NumberOfLayers; ++lidx)
   {
     // transform the plane/contour (the actual actor) to the corresponding view (axial, coronal or sagittal)
     localStorage->m_LayerActorVector[lidx]->SetUserTransform(trans);
     // transform the origin to center based coordinates, because MITK is center based.
     localStorage->m_LayerActorVector[lidx]->SetPosition(
       -0.5 * localStorage->m_mmPerPixel[0], -0.5 * localStorage->m_mmPerPixel[1], 0.0);
   }
   // same for outline actor
   localStorage->m_OutlineActor->SetUserTransform(trans);
   localStorage->m_OutlineActor->SetPosition(
     -0.5 * localStorage->m_mmPerPixel[0], -0.5 * localStorage->m_mmPerPixel[1], 0.0);
   // same for outline shadow actor
   localStorage->m_OutlineShadowActor->SetUserTransform(trans);
   localStorage->m_OutlineShadowActor->SetPosition(
     -0.5 * localStorage->m_mmPerPixel[0], -0.5 * localStorage->m_mmPerPixel[1], 0.0);
 }
 
 void mitk::LabelSetImageVtkMapper2D::SetDefaultProperties(mitk::DataNode *node,
                                                           mitk::BaseRenderer *renderer,
                                                           bool overwrite)
 {
   // add/replace the following properties
   node->SetProperty("opacity", FloatProperty::New(1.0f), renderer);
   node->SetProperty("binary", BoolProperty::New(false), renderer);
 
   mitk::RenderingModeProperty::Pointer renderingModeProperty =
     mitk::RenderingModeProperty::New(RenderingModeProperty::LOOKUPTABLE_LEVELWINDOW_COLOR);
   node->SetProperty("Image Rendering.Mode", renderingModeProperty, renderer);
 
   mitk::LevelWindow levelwindow(32767.5, 65535);
   mitk::LevelWindowProperty::Pointer levWinProp = mitk::LevelWindowProperty::New(levelwindow);
 
   levWinProp->SetLevelWindow(levelwindow);
   node->SetProperty("levelwindow", levWinProp, renderer);
 
   node->SetProperty("labelset.contour.active", BoolProperty::New(true), renderer);
   node->SetProperty("labelset.contour.width", FloatProperty::New(2.0), renderer);
 
   Superclass::SetDefaultProperties(node, renderer, overwrite);
 }
 
 mitk::LabelSetImageVtkMapper2D::LocalStorage::~LocalStorage()
 {
 }
 
 mitk::LabelSetImageVtkMapper2D::LocalStorage::LocalStorage()
 {
   // Do as much actions as possible in here to avoid double executions.
   m_Plane = vtkSmartPointer<vtkPlaneSource>::New();
   m_Actors = vtkSmartPointer<vtkPropAssembly>::New();
   m_OutlinePolyData = vtkSmartPointer<vtkPolyData>::New();
   m_EmptyPolyData = vtkSmartPointer<vtkPolyData>::New();
   m_OutlineActor = vtkSmartPointer<vtkActor>::New();
   m_OutlineMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
   m_OutlineShadowActor = vtkSmartPointer<vtkActor>::New();
 
   m_NumberOfLayers = 0;
   m_mmPerPixel = nullptr;
 
   m_OutlineActor->SetMapper(m_OutlineMapper);
   m_OutlineShadowActor->SetMapper(m_OutlineMapper);
 
   m_OutlineActor->SetVisibility(false);
   m_OutlineShadowActor->SetVisibility(false);
 }
diff --git a/Modules/Segmentation/Algorithms/mitkDiffImageApplier.cpp b/Modules/Segmentation/Algorithms/mitkDiffImageApplier.cpp
index 86ccf33984..b584e07da9 100644
--- a/Modules/Segmentation/Algorithms/mitkDiffImageApplier.cpp
+++ b/Modules/Segmentation/Algorithms/mitkDiffImageApplier.cpp
@@ -1,376 +1,376 @@
 /*============================================================================
 
 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 "mitkDiffImageApplier.h"
 
 #include "mitkApplyDiffImageOperation.h"
 #include "mitkImageAccessByItk.h"
 #include "mitkImageCast.h"
 #include "mitkImageTimeSelector.h"
 #include "mitkRenderingManager.h"
 #include "mitkSegmentationInterpolationController.h"
 
 #include <mitkIOUtil.h>
 
 #include <itkImageRegionConstIterator.h>
 #include <itkImageSliceIteratorWithIndex.h>
 
 #include <type_traits>
 
 mitk::DiffImageApplier::DiffImageApplier()
   : m_Image(nullptr),
     m_SliceDifferenceImage(nullptr),
     m_SliceIndex(0),
     m_SliceDimension(0),
     m_TimeStep(0),
     m_Dimension0(0),
     m_Dimension1(0),
     m_DestinationLabel(std::numeric_limits<mitk::Label::PixelType>::max()),
     m_Factor(1.0)
 {
 }
 
 mitk::DiffImageApplier::~DiffImageApplier()
 {
 }
 
 void mitk::DiffImageApplier::SetDestinationLabel(mitk::Label::PixelType label)
 {
   m_DestinationLabel = label;
 }
 
 void mitk::DiffImageApplier::ExecuteOperation(Operation *operation)
 {
   auto *imageOperation = dynamic_cast<ApplyDiffImageOperation *>(operation);
   if (imageOperation // we actually have the kind of operation that we can handle
       &&
       imageOperation->IsImageStillValid()) // AND the image is not yet deleted
   {
     m_Image = imageOperation->GetImage();
     Image::Pointer image3D = m_Image; // will be changed later in case of 3D+t
 
     m_SliceDifferenceImage = imageOperation->GetDiffImage();
     m_TimeStep = imageOperation->GetTimeStep();
 
     m_Factor = imageOperation->GetFactor();
 
     if (m_SliceDifferenceImage->GetDimension() == 2)
     {
       m_SliceIndex = imageOperation->GetSliceIndex();
       m_SliceDimension = imageOperation->GetSliceDimension();
       switch (m_SliceDimension)
       {
         default:
         case 2:
           m_Dimension0 = 0;
           m_Dimension1 = 1;
           break;
         case 1:
           m_Dimension0 = 0;
           m_Dimension1 = 2;
           break;
         case 0:
           m_Dimension0 = 1;
           m_Dimension1 = 2;
           break;
       }
 
       if (m_SliceDifferenceImage->GetDimension() != 2 || (m_Image->GetDimension() < 3 || m_Image->GetDimension() > 4) ||
           m_SliceDifferenceImage->GetDimension(0) != m_Image->GetDimension(m_Dimension0) ||
           m_SliceDifferenceImage->GetDimension(1) != m_Image->GetDimension(m_Dimension1) ||
           m_SliceIndex >= m_Image->GetDimension(m_SliceDimension))
       {
         itkExceptionMacro(
           "Slice and image dimensions differ or slice index is too large. Sorry, cannot work like this.");
         return;
       }
 
       if (m_Image->GetDimension() == 4)
       {
         ImageTimeSelector::Pointer timeSelector = ImageTimeSelector::New();
         timeSelector->SetInput(m_Image);
         timeSelector->SetTimeNr(m_TimeStep);
         timeSelector->UpdateLargestPossibleRegion();
         image3D = timeSelector->GetOutput();
       }
 
       AccessFixedDimensionByItk(image3D, ItkImageSwitch2DDiff, 3);
 
       if (m_Factor == 1 || m_Factor == -1)
       {
         if (m_Factor == -1)
         {
           // multiply diff pixels by factor and then send this diff slice
           AccessFixedDimensionByItk(m_SliceDifferenceImage, ItkInvertPixelValues, 2);
         }
 
         // just send the diff to SegmentationInterpolationController
         SegmentationInterpolationController *interpolator =
           SegmentationInterpolationController::InterpolatorForImage(m_Image);
         if (interpolator)
         {
           interpolator->BlockModified(true);
           interpolator->SetChangedSlice(m_SliceDifferenceImage, m_SliceDimension, m_SliceIndex, m_TimeStep);
         }
 
         m_Image->Modified();
 
         if (interpolator)
         {
           interpolator->BlockModified(false);
         }
 
         if (m_Factor == -1) // return to normal values
         {
           AccessFixedDimensionByItk(m_SliceDifferenceImage, ItkInvertPixelValues, 2);
         }
       }
       else // no trivial case, too lazy to do something else
       {
         m_Image->Modified(); // check if interpolation is called. prefer to send diff directly
       }
 
       RenderingManager::GetInstance()->RequestUpdateAll();
     }
     else if (m_SliceDifferenceImage->GetDimension() == 3)
     {
       // ...
       if (m_SliceDifferenceImage->GetDimension(0) != m_Image->GetDimension(0) ||
           m_SliceDifferenceImage->GetDimension(1) != m_Image->GetDimension(1) ||
           m_SliceDifferenceImage->GetDimension(2) != m_Image->GetDimension(2) || m_TimeStep >= m_Image->GetDimension(3))
       {
         itkExceptionMacro("Diff image size differs from original image size. Sorry, cannot work like this.");
         return;
       }
 
       if (m_Image->GetDimension() == 4)
       {
         ImageTimeSelector::Pointer timeSelector = ImageTimeSelector::New();
         timeSelector->SetInput(m_Image);
         timeSelector->SetTimeNr(m_TimeStep);
         timeSelector->UpdateLargestPossibleRegion();
         image3D = timeSelector->GetOutput();
       }
 
       auto labelSetImage = dynamic_cast<mitk::LabelSetImage* >(m_Image.GetPointer());
 
       // this will do a long long if/else to find out both pixel types
       TransferLabelContentAtTimeStep(
         m_SliceDifferenceImage,
         labelSetImage,
-        labelSetImage->GetActiveLabelSet(),
+        labelSetImage->GetConstLabelsInGroup(labelSetImage->GetActiveLayer()),
         m_TimeStep,
         0,
         0,
         false,
         {{1, m_DestinationLabel}},
         mitk::MultiLabelSegmentation::MergeStyle::Merge,
         mitk::MultiLabelSegmentation::OverwriteStyle::RegardLocks);
 
       if (m_Factor == 1 || m_Factor == -1)
       {
         if (m_Factor == -1)
         {
           // multiply diff pixels by factor and then send this diff slice
           AccessFixedDimensionByItk(m_SliceDifferenceImage, ItkInvertPixelValues, 3);
         }
 
         // just send the diff to SegmentationInterpolationController
         SegmentationInterpolationController *interpolator =
           SegmentationInterpolationController::InterpolatorForImage(m_Image);
         if (interpolator)
         {
           interpolator->BlockModified(true);
           interpolator->SetChangedVolume(m_SliceDifferenceImage, m_TimeStep);
         }
 
         if (interpolator)
         {
           interpolator->BlockModified(false);
         }
 
         if (m_Factor == -1) // return to normal values
         {
           AccessFixedDimensionByItk(m_SliceDifferenceImage, ItkInvertPixelValues, 3);
         }
       }
       else // no trivial case, too lazy to do something else
       {
         m_Image->Modified(); // check if interpolation is called. prefer to send diff directly
       }
 
       RenderingManager::GetInstance()->RequestUpdateAll();
     }
     else
     {
       itkExceptionMacro("Diff image must be 2D or 3D. Sorry, cannot work like this.");
       return;
     }
   }
 
   m_Image = nullptr;
   m_SliceDifferenceImage = nullptr;
 }
 
 mitk::DiffImageApplier *mitk::DiffImageApplier::GetInstanceForUndo()
 {
   static DiffImageApplier::Pointer s_Instance = DiffImageApplier::New();
 
   return s_Instance;
 }
 
 // basically copied from mitk/Core/Algorithms/mitkImageAccessByItk.h
 #define myMITKDiffImageApplierFilterAccessByItk(mitkImage, itkImageTypeFunction, pixeltype, dimension, itkimage2)      \
   if (typeId == MapPixelComponentType<pixeltype>::value)                                                               \
   \
 {                                                                                                                 \
     typedef itk::Image<pixeltype, dimension> ImageType;                                                                \
     typedef mitk::ImageToItk<ImageType> ImageToItkType;                                                                \
     itk::SmartPointer<ImageToItkType> imagetoitk = ImageToItkType::New();                                              \
     const mitk::Image *constImage = mitkImage;                                                                         \
     mitk::Image *nonConstImage = const_cast<mitk::Image *>(constImage);                                                \
     nonConstImage->Update();                                                                                           \
     imagetoitk->SetInput(nonConstImage);                                                                               \
     imagetoitk->Update();                                                                                              \
     itkImageTypeFunction(imagetoitk->GetOutput(), itkimage2);                                                          \
   \
 }
 
 #define myMITKDiffImageApplierFilterAccessAllTypesByItk(mitkImage, itkImageTypeFunction, dimension, itkimage2)                                                                                                                                                                                                                                                                                                                                                                                                                              \
   \
 {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      \
     myMITKDiffImageApplierFilterAccessByItk(mitkImage, itkImageTypeFunction, double, dimension, itkimage2) else myMITKDiffImageApplierFilterAccessByItk(                                                                                                                                                                                                                                                                                                                                                                                    \
       mitkImage,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            \
       itkImageTypeFunction,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 \
       float,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                \
       dimension,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            \
       itkimage2) else myMITKDiffImageApplierFilterAccessByItk(mitkImage, itkImageTypeFunction, int, dimension, itkimage2) else myMITKDiffImageApplierFilterAccessByItk(mitkImage,                                                                                                                                                                                                                                                                                                                                                           \
                                                                                                                                                                        itkImageTypeFunction,                                                                                                                                                                                                                                                                                                                                                \
                                                                                                                                                                        unsigned int,                                                                                                                                                                                                                                                                                                                                                        \
                                                                                                                                                                        dimension,                                                                                                                                                                                                                                                                                                                                                           \
                                                                                                                                                                        itkimage2) else myMITKDiffImageApplierFilterAccessByItk(mitkImage, itkImageTypeFunction, short, dimension, itkimage2) else myMITKDiffImageApplierFilterAccessByItk(mitkImage, itkImageTypeFunction, unsigned short, dimension, itkimage2) else myMITKDiffImageApplierFilterAccessByItk(mitkImage,                                                                    \
                                                                                                                                                                                                                                                                                                                                                                                                                                                               itkImageTypeFunction,                                                         \
                                                                                                                                                                                                                                                                                                                                                                                                                                                               char,                                                                         \
                                                                                                                                                                                                                                                                                                                                                                                                                                                               dimension,                                                                    \
                                                                                                                                                                                                                                                                                                                                                                                                                                                               itkimage2) else myMITKDiffImageApplierFilterAccessByItk(mitkImage,            \
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       itkImageTypeFunction, \
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       unsigned char,        \
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       dimension,            \
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       itkimage2)            \
   \
 }
 
 template <typename TPixel, unsigned int VImageDimension>
 void mitk::DiffImageApplier::ItkImageSwitch2DDiff(itk::Image<TPixel, VImageDimension> *itkImage)
 {
   const auto typeId = m_SliceDifferenceImage->GetPixelType().GetComponentType();
 
   myMITKDiffImageApplierFilterAccessAllTypesByItk(m_SliceDifferenceImage, ItkImageProcessing2DDiff, 2, itkImage);
 }
 
 template <typename TPixel, unsigned int VImageDimension>
 void mitk::DiffImageApplier::ItkImageSwitch3DDiff(itk::Image<TPixel, VImageDimension> *itkImage)
 {
   const auto typeId = m_SliceDifferenceImage->GetPixelType().GetComponentType();
 
   myMITKDiffImageApplierFilterAccessAllTypesByItk(m_SliceDifferenceImage, ItkImageProcessing3DDiff, 3, itkImage);
 }
 
 template <typename TPixel1, unsigned int VImageDimension1, typename TPixel2, unsigned int VImageDimension2>
 void mitk::DiffImageApplier::ItkImageProcessing2DDiff(itk::Image<TPixel1, VImageDimension1> *diffImage,
                                                       itk::Image<TPixel2, VImageDimension2> *outputImage)
 {
   typedef itk::Image<TPixel1, VImageDimension1> DiffImageType;
   typedef itk::Image<TPixel2, VImageDimension2> VolumeImageType;
 
   typedef itk::ImageSliceIteratorWithIndex<VolumeImageType> OutputSliceIteratorType;
   typedef itk::ImageRegionConstIterator<DiffImageType> DiffSliceIteratorType;
 
   typename VolumeImageType::RegionType sliceInVolumeRegion;
 
   sliceInVolumeRegion = outputImage->GetLargestPossibleRegion();
   sliceInVolumeRegion.SetSize(m_SliceDimension, 1);             // just one slice
   sliceInVolumeRegion.SetIndex(m_SliceDimension, m_SliceIndex); // exactly this slice, please
 
   OutputSliceIteratorType outputIterator(outputImage, sliceInVolumeRegion);
   outputIterator.SetFirstDirection(m_Dimension0);
   outputIterator.SetSecondDirection(m_Dimension1);
 
   DiffSliceIteratorType diffIterator(diffImage, diffImage->GetLargestPossibleRegion());
 
   // iterate over output slice (and over input slice simultaneously)
   outputIterator.GoToBegin();
   diffIterator.GoToBegin();
   while (!outputIterator.IsAtEnd())
   {
     while (!outputIterator.IsAtEndOfSlice())
     {
       while (!outputIterator.IsAtEndOfLine())
       {
         TPixel2 newValue = outputIterator.Get() + (TPixel2)((double)diffIterator.Get() * m_Factor);
         outputIterator.Set(newValue);
         ++outputIterator;
         ++diffIterator;
       }
       outputIterator.NextLine();
     }
     outputIterator.NextSlice();
   }
 }
 
 template <typename TPixel1, unsigned int VImageDimension1, typename TPixel2, unsigned int VImageDimension2>
 void mitk::DiffImageApplier::ItkImageProcessing3DDiff(itk::Image<TPixel1, VImageDimension1> *diffImage,
                                                       itk::Image<TPixel2, VImageDimension2> *outputImage)
 {
   typedef itk::Image<TPixel1, VImageDimension1> DiffImageType;
   typedef itk::Image<TPixel2, VImageDimension2> VolumeImageType;
 
   typedef itk::ImageRegionIterator<VolumeImageType> OutputSliceIteratorType;
   typedef itk::ImageRegionConstIterator<DiffImageType> DiffSliceIteratorType;
 
   OutputSliceIteratorType outputIterator(outputImage, outputImage->GetLargestPossibleRegion());
   DiffSliceIteratorType diffIterator(diffImage, diffImage->GetLargestPossibleRegion());
 
   // iterate over output slice (and over input slice simultaneously)
   outputIterator.GoToBegin();
   diffIterator.GoToBegin();
   while (!outputIterator.IsAtEnd())
   {
     TPixel2 newValue = outputIterator.Get() + (TPixel2)((double)diffIterator.Get() * m_Factor);
     outputIterator.Set(newValue);
     ++outputIterator;
     ++diffIterator;
   }
 }
 
 #ifdef _MSC_VER
 #  pragma warning(push)
 #  pragma warning(disable:4146) // unary minus operator applied to unsigned type, result still unsigned
 #endif
 
 template <typename TPixel, unsigned int VImageDimension>
 void mitk::DiffImageApplier::ItkInvertPixelValues(itk::Image<TPixel, VImageDimension> *itkImage)
 {
   typedef itk::ImageRegionIterator<itk::Image<TPixel, VImageDimension>> IteratorType;
   IteratorType iter(itkImage, itkImage->GetLargestPossibleRegion());
 
   iter.GoToBegin();
   while (!iter.IsAtEnd())
   {
     iter.Set(-(iter.Get()));
     ++iter;
   }
 }
 
 #ifdef _MSC_VER
 #  pragma warning(pop)
 #endif
diff --git a/Modules/Segmentation/Algorithms/mitkShowSegmentationAsSurface.cpp b/Modules/Segmentation/Algorithms/mitkShowSegmentationAsSurface.cpp
index f64e713f13..ec182eeee7 100644
--- a/Modules/Segmentation/Algorithms/mitkShowSegmentationAsSurface.cpp
+++ b/Modules/Segmentation/Algorithms/mitkShowSegmentationAsSurface.cpp
@@ -1,333 +1,333 @@
 /*============================================================================
 
 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 "mitkShowSegmentationAsSurface.h"
 #include "mitkManualSegmentationToSurfaceFilter.h"
 #include "mitkVtkRepresentationProperty.h"
 #include <mitkCoreObjectFactory.h>
 #include <mitkLabelSetImage.h>
 #include <vtkPolyDataNormals.h>
 
 namespace mitk
 {
   ShowSegmentationAsSurface::ShowSegmentationAsSurface()
     : m_UIDGeneratorSurfaces("Surface_"),
       m_IsLabelSetImage(false)
   {
   }
 
   ShowSegmentationAsSurface::~ShowSegmentationAsSurface()
   {
   }
 
   void ShowSegmentationAsSurface::Initialize(const NonBlockingAlgorithm *other)
   {
     Superclass::Initialize(other);
 
     bool syncVisibility(false);
 
     if (other)
     {
       other->GetParameter("Sync visibility", syncVisibility);
     }
 
     SetParameter("Sync visibility", syncVisibility);
     SetParameter("Median kernel size", 3u);
     SetParameter("Apply median", true);
     SetParameter("Smooth", true);
     SetParameter("Gaussian SD", 1.5);
     SetParameter("Decimate mesh", true);
     SetParameter("Decimation rate", 0.8);
     SetParameter("Wireframe", false);
 
     m_SurfaceNodes.clear();
   }
 
   bool ShowSegmentationAsSurface::ReadyToRun()
   {
     try
     {
       Image::Pointer image;
       GetPointerParameter("Input", image);
 
       return image.IsNotNull() && GetGroupNode();
     }
     catch (std::invalid_argument &)
     {
       return false;
     }
   }
 
   bool ShowSegmentationAsSurface::ThreadedUpdateFunction()
   {
     Image::Pointer image;
     GetPointerParameter("Input", image);
 
     bool smooth(true);
     GetParameter("Smooth", smooth);
 
     bool applyMedian(true);
     GetParameter("Apply median", applyMedian);
 
     bool decimateMesh(true);
     GetParameter("Decimate mesh", decimateMesh);
 
     unsigned int medianKernelSize(3);
     GetParameter("Median kernel size", medianKernelSize);
 
     double gaussianSD(1.5);
     GetParameter("Gaussian SD", gaussianSD);
 
     double reductionRate(0.8);
     GetParameter("Decimation rate", reductionRate);
 
     MITK_INFO << "Creating polygon model with smoothing " << smooth << " gaussianSD " << gaussianSD << " median "
               << applyMedian << " median kernel " << medianKernelSize << " mesh reduction " << decimateMesh
               << " reductionRate " << reductionRate;
 
     auto labelSetImage = dynamic_cast<LabelSetImage *>(image.GetPointer());
 
     if (nullptr != labelSetImage)
     {
-      auto numberOfLayers = labelSetImage->GetNumberOfLayers();
+      const auto labels = labelSetImage->GetLabels();
 
       for (decltype(numberOfLayers) layerIndex = 0; layerIndex < numberOfLayers; ++layerIndex)
       {
         auto labelSet = labelSetImage->GetLabelSet(layerIndex);
 
         for (auto labelIter = labelSet->IteratorConstBegin(); labelIter != labelSet->IteratorConstEnd(); ++labelIter)
         {
           if (0 == labelIter->first)
             continue; // Do not process background label
 
           auto labelImage = labelSetImage->CreateLabelMask(labelIter->first, false, layerIndex);
 
           if (labelImage.IsNull())
             continue;
 
           auto labelSurface = this->ConvertBinaryImageToSurface(labelImage);
 
           if (labelSurface.IsNull())
             continue;
 
           auto* polyData = labelSurface->GetVtkPolyData();
 
           if (smooth && (polyData->GetNumberOfPoints() < 1 || polyData->GetNumberOfCells() < 1))
           {
             MITK_WARN << "Label \"" << labelIter->second->GetName() << "\" didn't produce any smoothed surface data (try again without smoothing).";
             continue;
           }
 
           auto node = DataNode::New();
           node->SetData(labelSurface);
           node->SetColor(labelIter->second->GetColor());
           node->SetName(labelIter->second->GetName());
 
           m_SurfaceNodes.push_back(node);
         }
       }
     }
     else
     {
       auto surface = this->ConvertBinaryImageToSurface(image);
 
       if (surface.IsNotNull())
       {
         auto* polyData = surface->GetVtkPolyData();
 
         if (smooth && (polyData->GetNumberOfPoints() < 1 || polyData->GetNumberOfCells() < 1))
         {
           MITK_WARN << "Could not produce smoothed surface data (try again without smoothing).";
         }
         else
         {
           auto node = DataNode::New();
           node->SetData(surface);
           m_SurfaceNodes.push_back(node);
         }
       }
     }
 
     m_IsLabelSetImage = nullptr != labelSetImage;
     return true;
   }
 
   void ShowSegmentationAsSurface::ThreadedUpdateSuccessful()
   {
     for (const auto &node : m_SurfaceNodes)
     {
       bool wireframe = false;
       GetParameter("Wireframe", wireframe);
 
       if (wireframe)
       {
         auto representation = dynamic_cast<VtkRepresentationProperty *>(node->GetProperty("material.representation"));
         if (nullptr != representation)
           representation->SetRepresentationToWireframe();
       }
 
       node->SetProperty("opacity", FloatProperty::New(0.3f));
       node->SetProperty("line width", FloatProperty::New(1.0f));
       node->SetProperty("scalar visibility", BoolProperty::New(false));
 
       auto name = node->GetName();
       auto groupNode = this->GetGroupNode();
 
       if (!m_IsLabelSetImage)
       {
         if ((name.empty() || DataNode::NO_NAME_VALUE() == name) && nullptr != groupNode)
           name = groupNode->GetName();
 
         if (name.empty())
           name = "Surface";
       }
 
       bool smooth = true;
       GetParameter("Smooth", smooth);
 
       if (smooth)
         name.append(" (smoothed)");
 
       node->SetName(name);
 
       if (!m_IsLabelSetImage)
       {
         auto colorProp = groupNode->GetProperty("color");
 
         if (nullptr != colorProp)
         {
           node->ReplaceProperty("color", colorProp->Clone());
         }
         else
         {
           node->SetProperty("color", ColorProperty::New(1.0, 1.0, 0.0));
         }
       }
 
       bool showResult = true;
       GetParameter("Show result", showResult);
 
       bool syncVisibility = false;
       GetParameter("Sync visibility", syncVisibility);
 
       auto visibleProp = groupNode->GetProperty("visible");
 
       if (nullptr != visibleProp && syncVisibility)
       {
         node->ReplaceProperty("visible", visibleProp->Clone());
       }
       else
       {
         node->SetProperty("visible", BoolProperty::New(showResult));
       }
 
       if (!m_IsLabelSetImage)
       {
         Image::Pointer image;
         GetPointerParameter("Input", image);
 
         if (image.IsNotNull())
         {
           auto organTypeProp = image->GetProperty("organ type");
 
           if (nullptr != organTypeProp)
             node->GetData()->SetProperty("organ type", organTypeProp);
         }
       }
 
       this->InsertBelowGroupNode(node);
     }
 
     Superclass::ThreadedUpdateSuccessful();
   }
 
   Surface::Pointer ShowSegmentationAsSurface::ConvertBinaryImageToSurface(Image::Pointer binaryImage)
   {
     bool smooth = true;
     GetParameter("Smooth", smooth);
 
     bool applyMedian = true;
     GetParameter("Apply median", applyMedian);
 
     bool decimateMesh = true;
     GetParameter("Decimate mesh", decimateMesh);
 
     unsigned int medianKernelSize = 3;
     GetParameter("Median kernel size", medianKernelSize);
 
     double gaussianSD = 1.5;
     GetParameter("Gaussian SD", gaussianSD);
 
     double reductionRate = 0.8;
     GetParameter("Decimation rate", reductionRate);
 
     auto filter = ManualSegmentationToSurfaceFilter::New();
     filter->SetInput(binaryImage);
     filter->SetThreshold(0.5);
     filter->SetUseGaussianImageSmooth(smooth);
     filter->SetSmooth(smooth);
     filter->SetMedianFilter3D(applyMedian);
 
     if (smooth)
     {
       filter->InterpolationOn();
       filter->SetGaussianStandardDeviation(gaussianSD);
     }
 
     if (applyMedian)
       filter->SetMedianKernelSize(medianKernelSize, medianKernelSize, medianKernelSize);
 
     // Fix to avoid VTK warnings (see T5390)
     if (binaryImage->GetDimension() > 3)
       decimateMesh = false;
 
     if (decimateMesh)
     {
       filter->SetDecimate(ImageToSurfaceFilter::QuadricDecimation);
       filter->SetTargetReduction(reductionRate);
     }
     else
     {
       filter->SetDecimate(ImageToSurfaceFilter::NoDecimation);
     }
 
     filter->UpdateLargestPossibleRegion();
 
     auto surface = filter->GetOutput();
     auto polyData = surface->GetVtkPolyData();
 
     if (nullptr == polyData)
       throw std::logic_error("Could not create polygon model");
 
     polyData->SetVerts(nullptr);
     polyData->SetLines(nullptr);
 
     if (smooth || applyMedian || decimateMesh)
     {
       auto normals = vtkSmartPointer<vtkPolyDataNormals>::New();
 
       normals->AutoOrientNormalsOn();
       normals->FlipNormalsOff();
       normals->SetInputData(polyData);
 
       normals->Update();
 
       surface->SetVtkPolyData(normals->GetOutput());
     }
     else
     {
       surface->SetVtkPolyData(polyData);
     }
 
     return surface;
   }
 }
diff --git a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropperView.cpp b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropperView.cpp
index c8ae768dbd..53ee838915 100644
--- a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropperView.cpp
+++ b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropperView.cpp
@@ -1,510 +1,510 @@
 /*============================================================================
 
 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 "QmitkImageCropperView.h"
 
 #include <mitkBoundingShapeCropper.h>
 #include <mitkImageStatisticsHolder.h>
 #include <mitkInteractionConst.h>
 #include <mitkITKImageImport.h>
 #include <mitkLabelSetImage.h>
 #include <mitkNodePredicateDataType.h>
 #include <mitkNodePredicateAnd.h>
 #include <mitkNodePredicateNot.h>
 #include <mitkNodePredicateProperty.h>
 #include <mitkNodePredicateFunction.h>
 #include <mitkRenderingManager.h>
 
 #include <usModuleRegistry.h>
 
 #include <QMessageBox>
 
 const std::string QmitkImageCropperView::VIEW_ID = "org.mitk.views.qmitkimagecropper";
 
 QmitkImageCropperView::QmitkImageCropperView(QObject *)
   : m_ParentWidget(nullptr)
   , m_BoundingShapeInteractor(nullptr)
   , m_CropOutsideValue(0)
 {
   CreateBoundingShapeInteractor(false);
 }
 
 QmitkImageCropperView::~QmitkImageCropperView()
 {
   //disable interactor
   if (m_BoundingShapeInteractor != nullptr)
   {
     m_BoundingShapeInteractor->SetDataNode(nullptr);
     m_BoundingShapeInteractor->EnableInteraction(false);
   }
 }
 
 void QmitkImageCropperView::CreateQtPartControl(QWidget *parent)
 {
   // create GUI widgets from the Qt Designer's .ui file
   m_Controls.setupUi(parent);
 
   m_Controls.imageSelectionWidget->SetDataStorage(GetDataStorage());
   m_Controls.imageSelectionWidget->SetNodePredicate(
     mitk::NodePredicateAnd::New(mitk::TNodePredicateDataType<mitk::Image>::New(),
                                 mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))));
   m_Controls.imageSelectionWidget->SetSelectionIsOptional(true);
   m_Controls.imageSelectionWidget->SetAutoSelectNewNodes(true);
   m_Controls.imageSelectionWidget->SetEmptyInfo(QString("Please select an image node"));
   m_Controls.imageSelectionWidget->SetPopUpTitel(QString("Select image node"));
 
   connect(m_Controls.imageSelectionWidget, &QmitkSingleNodeSelectionWidget::CurrentSelectionChanged,
     this, &QmitkImageCropperView::OnImageSelectionChanged);
 
   m_Controls.boundingBoxSelectionWidget->SetDataStorage(GetDataStorage());
   m_Controls.boundingBoxSelectionWidget->SetNodePredicate(mitk::NodePredicateAnd::New(
     mitk::TNodePredicateDataType<mitk::GeometryData>::New(),
     mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))));
   m_Controls.boundingBoxSelectionWidget->SetSelectionIsOptional(true);
   m_Controls.boundingBoxSelectionWidget->SetAutoSelectNewNodes(true);
   m_Controls.boundingBoxSelectionWidget->SetEmptyInfo(QString("Please select a bounding box"));
   m_Controls.boundingBoxSelectionWidget->SetPopUpTitel(QString("Select bounding box node"));
 
   connect(m_Controls.boundingBoxSelectionWidget, &QmitkSingleNodeSelectionWidget::CurrentSelectionChanged,
     this, &QmitkImageCropperView::OnBoundingBoxSelectionChanged);
 
   connect(m_Controls.buttonCreateNewBoundingBox, SIGNAL(clicked()), this, SLOT(OnCreateNewBoundingBox()));
   connect(m_Controls.buttonCropping, SIGNAL(clicked()), this, SLOT(OnCropping()));
   connect(m_Controls.buttonMasking, SIGNAL(clicked()), this, SLOT(OnMasking()));
   auto lambda = [this]()
   {
     m_Controls.groupImageSettings->setVisible(!m_Controls.groupImageSettings->isVisible());
   };
 
   connect(m_Controls.buttonAdvancedSettings, &ctkExpandButton::clicked, this, lambda);
 
   connect(m_Controls.spinBoxOutsidePixelValue, SIGNAL(valueChanged(int)), this, SLOT(OnSliderValueChanged(int)));
 
   SetDefaultGUI();
 
   m_ParentWidget = parent;
 
   this->OnImageSelectionChanged(m_Controls.imageSelectionWidget->GetSelectedNodes());
   this->OnBoundingBoxSelectionChanged(m_Controls.boundingBoxSelectionWidget->GetSelectedNodes());
 }
 
 void QmitkImageCropperView::OnImageSelectionChanged(QList<mitk::DataNode::Pointer>)
 {
   bool rotationEnabled = false;
   m_Controls.labelWarningRotation->setVisible(false);
 
   auto imageNode = m_Controls.imageSelectionWidget->GetSelectedNode();
   if (imageNode.IsNull())
   {
     SetDefaultGUI();
     return;
   }
 
   auto image = dynamic_cast<mitk::Image*>(imageNode->GetData());
   if (nullptr != image)
   {
     if (image->GetDimension() < 3)
     {
       QMessageBox::warning(nullptr,
         tr("Invalid image selected"),
         tr("ImageCropper only works with 3 or more dimensions."),
         QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton);
       SetDefaultGUI();
       return;
     }
 
     m_ParentWidget->setEnabled(true);
     m_Controls.buttonCreateNewBoundingBox->setEnabled(true);
 
     vtkSmartPointer<vtkMatrix4x4> imageMat = image->GetGeometry()->GetVtkMatrix();
     // check whether the image geometry is rotated; if so, no pixel aligned cropping or masking can be performed
     if ((imageMat->GetElement(1, 0) == 0.0) && (imageMat->GetElement(0, 1) == 0.0) &&
       (imageMat->GetElement(1, 2) == 0.0) && (imageMat->GetElement(2, 1) == 0.0) &&
       (imageMat->GetElement(2, 0) == 0.0) && (imageMat->GetElement(0, 2) == 0.0))
     {
       rotationEnabled = false;
       m_Controls.labelWarningRotation->setVisible(false);
     }
     else
     {
       rotationEnabled = true;
       m_Controls.labelWarningRotation->setStyleSheet(" QLabel { color: rgb(255, 0, 0) }");
       m_Controls.labelWarningRotation->setVisible(true);
     }
 
     this->CreateBoundingShapeInteractor(rotationEnabled);
 
     if (itk::IOPixelEnum::SCALAR == image->GetPixelType().GetPixelType())
     {
       // Might be changed with the upcoming new image statistics plugin
       //(recomputation might be very expensive for large images ;) )
       auto statistics = image->GetStatistics();
       auto minPixelValue = statistics->GetScalarValueMin();
       auto maxPixelValue = statistics->GetScalarValueMax();
 
       if (minPixelValue < std::numeric_limits<int>::min())
       {
         minPixelValue = std::numeric_limits<int>::min();
       }
       if (maxPixelValue > std::numeric_limits<int>::max())
       {
         maxPixelValue = std::numeric_limits<int>::max();
       }
 
       m_Controls.spinBoxOutsidePixelValue->setEnabled(true);
       m_Controls.spinBoxOutsidePixelValue->setMaximum(static_cast<int>(maxPixelValue));
       m_Controls.spinBoxOutsidePixelValue->setMinimum(static_cast<int>(minPixelValue));
       m_Controls.spinBoxOutsidePixelValue->setValue(static_cast<int>(minPixelValue));
     }
     else
     {
       m_Controls.spinBoxOutsidePixelValue->setEnabled(false);
     }
 
     unsigned int dim = image->GetDimension();
     if (dim < 2 || dim > 4)
     {
       m_ParentWidget->setEnabled(false);
     }
 
     if (m_Controls.boundingBoxSelectionWidget->GetSelectedNode().IsNotNull())
     {
       m_Controls.buttonCropping->setEnabled(true);
       m_Controls.buttonMasking->setEnabled(true);
       m_Controls.buttonAdvancedSettings->setEnabled(true);
       m_Controls.groupImageSettings->setEnabled(true);
     }
   }
 }
 
 void QmitkImageCropperView::OnBoundingBoxSelectionChanged(QList<mitk::DataNode::Pointer>)
 {
   auto boundingBoxNode = m_Controls.boundingBoxSelectionWidget->GetSelectedNode();
   if (boundingBoxNode.IsNull())
   {
     SetDefaultGUI();
 
     m_BoundingShapeInteractor->EnableInteraction(false);
     m_BoundingShapeInteractor->SetDataNode(nullptr);
 
     if (m_Controls.imageSelectionWidget->GetSelectedNode().IsNotNull())
     {
       m_Controls.buttonCreateNewBoundingBox->setEnabled(true);
     }
 
     return;
   }
 
   auto boundingBox = dynamic_cast<mitk::GeometryData*>(boundingBoxNode->GetData());
   if (nullptr != boundingBox)
   {
     // node newly selected
     boundingBoxNode->SetVisibility(true);
 
     m_BoundingShapeInteractor->EnableInteraction(true);
     m_BoundingShapeInteractor->SetDataNode(boundingBoxNode);
 
     mitk::RenderingManager::GetInstance()->InitializeViews();
 
     if (m_Controls.imageSelectionWidget->GetSelectedNode().IsNotNull())
     {
       m_Controls.buttonCropping->setEnabled(true);
       m_Controls.buttonMasking->setEnabled(true);
       m_Controls.buttonAdvancedSettings->setEnabled(true);
       m_Controls.groupImageSettings->setEnabled(true);
     }
   }
 }
 
 void QmitkImageCropperView::OnCreateNewBoundingBox()
 {
   auto imageNode = m_Controls.imageSelectionWidget->GetSelectedNode();
   if (imageNode.IsNull())
   {
     return;
   }
   if (nullptr == imageNode->GetData())
   {
     return;
   }
 
   QString name = QString::fromStdString(imageNode->GetName() + " Bounding Box");
 
   auto boundingShape = this->GetDataStorage()->GetNode(mitk::NodePredicateFunction::New([&name](const mitk::DataNode *node)
   {
     return 0 == node->GetName().compare(name.toStdString());
   }));
 
   if (nullptr != boundingShape)
   {
     name = this->AdaptBoundingObjectName(name);
   }
 
   // get current timestep to support 3d+t images
   auto renderWindowPart = this->GetRenderWindowPart(mitk::WorkbenchUtil::IRenderWindowPartStrategy::OPEN);
   const mitk::TimePointType timePoint = renderWindowPart->GetSelectedTimePoint();
   const auto imageGeometry = imageNode->GetData()->GetTimeGeometry()->GetGeometryForTimePoint(timePoint);
 
   auto boundingBox = mitk::GeometryData::New();
   boundingBox->SetGeometry(static_cast<mitk::Geometry3D*>(this->InitializeWithImageGeometry(imageGeometry)));
   auto boundingBoxNode = mitk::DataNode::New();
   boundingBoxNode->SetData(boundingBox);
   boundingBoxNode->SetProperty("name", mitk::StringProperty::New(name.toStdString()));
   boundingBoxNode->SetProperty("layer", mitk::IntProperty::New(99));
   boundingBoxNode->AddProperty("Bounding Shape.Handle Size Factor", mitk::DoubleProperty::New(0.02));
   boundingBoxNode->SetBoolProperty("pickable", true);
 
   if (!this->GetDataStorage()->Exists(boundingBoxNode))
   {
     GetDataStorage()->Add(boundingBoxNode, imageNode);
   }
 
   m_Controls.boundingBoxSelectionWidget->SetCurrentSelectedNode(boundingBoxNode);
 }
 
 void QmitkImageCropperView::OnCropping()
 {
   this->ProcessImage(false);
 }
 
 void QmitkImageCropperView::OnMasking()
 {
   this->ProcessImage(true);
 }
 
 void QmitkImageCropperView::OnSliderValueChanged(int slidervalue)
 {
   m_CropOutsideValue = slidervalue;
 }
 
 void QmitkImageCropperView::CreateBoundingShapeInteractor(bool rotationEnabled)
 {
   if (m_BoundingShapeInteractor.IsNull())
   {
     m_BoundingShapeInteractor = mitk::BoundingShapeInteractor::New();
     m_BoundingShapeInteractor->LoadStateMachine("BoundingShapeInteraction.xml", us::ModuleRegistry::GetModule("MitkBoundingShape"));
     m_BoundingShapeInteractor->SetEventConfig("BoundingShapeMouseConfig.xml", us::ModuleRegistry::GetModule("MitkBoundingShape"));
   }
   m_BoundingShapeInteractor->SetRotationEnabled(rotationEnabled);
 }
 
 mitk::Geometry3D::Pointer QmitkImageCropperView::InitializeWithImageGeometry(const mitk::BaseGeometry* geometry) const
 {
   // convert a BaseGeometry into a Geometry3D (otherwise IO is not working properly)
   if (geometry == nullptr)
     mitkThrow() << "Geometry is not valid.";
 
   auto boundingGeometry = mitk::Geometry3D::New();
   boundingGeometry->SetBounds(geometry->GetBounds());
   boundingGeometry->SetImageGeometry(geometry->GetImageGeometry());
   boundingGeometry->SetOrigin(geometry->GetOrigin());
   boundingGeometry->SetSpacing(geometry->GetSpacing());
   boundingGeometry->SetIndexToWorldTransform(geometry->GetIndexToWorldTransform()->Clone());
   boundingGeometry->Modified();
   return boundingGeometry;
 }
 
 void QmitkImageCropperView::ProcessImage(bool mask)
 {
   auto renderWindowPart = this->GetRenderWindowPart(mitk::WorkbenchUtil::IRenderWindowPartStrategy::OPEN);
   const auto timePoint = renderWindowPart->GetSelectedTimePoint();
 
   auto imageNode = m_Controls.imageSelectionWidget->GetSelectedNode();
   if (imageNode.IsNull())
   {
     QMessageBox::information(nullptr, "Warning", "Please load and select an image before starting image processing.");
     return;
   }
 
   auto boundingBoxNode = m_Controls.boundingBoxSelectionWidget->GetSelectedNode();
   if (boundingBoxNode.IsNull())
   {
     QMessageBox::information(nullptr, "Warning", "Please load and select a cropping object before starting image processing.");
     return;
   }
 
   if (!imageNode->GetData()->GetTimeGeometry()->IsValidTimePoint(timePoint))
   {
     QMessageBox::information(nullptr, "Warning", "Please select a time point that is within the time bounds of the selected image.");
     return;
   }
   const auto timeStep = imageNode->GetData()->GetTimeGeometry()->TimePointToTimeStep(timePoint);
 
-  auto image = dynamic_cast<mitk::Image*>(imageNode->GetData());
-  auto boundingBox = dynamic_cast<mitk::GeometryData*>(boundingBoxNode->GetData());
+  const auto image = dynamic_cast<mitk::Image*>(imageNode->GetData());
+  const auto boundingBox = dynamic_cast<mitk::GeometryData*>(boundingBoxNode->GetData());
   if (nullptr != image && nullptr != boundingBox)
   {
     // Check if initial node name is already in box name
     std::string imagePrefix = "";
     if (boundingBoxNode->GetName().find(imageNode->GetName()) != 0)
     {
       imagePrefix = imageNode->GetName() + "_";
     }
 
     QString imageName;
     if (mask)
     {
       imageName = QString::fromStdString(imagePrefix + boundingBoxNode->GetName() + "_masked");
     }
     else
     {
       imageName = QString::fromStdString(imagePrefix + boundingBoxNode->GetName() + "_cropped");
     }
 
     if (m_Controls.checkBoxCropTimeStepOnly->isChecked())
     {
       imageName = imageName + "_T" + QString::number(timeStep);
     }
 
     // image and bounding shape ok, set as input
     auto croppedImageNode = mitk::DataNode::New();
     auto cutter = mitk::BoundingShapeCropper::New();
     cutter->SetGeometry(boundingBox);
 
     // adjustable in advanced settings
     cutter->SetUseWholeInputRegion(mask); //either mask (mask=true) or crop (mask=false)
     cutter->SetOutsideValue(m_CropOutsideValue);
     cutter->SetUseCropTimeStepOnly(m_Controls.checkBoxCropTimeStepOnly->isChecked());
     cutter->SetCurrentTimeStep(timeStep);
 
     // TODO: Add support for MultiLayer (right now only Mulitlabel support)
-    auto labelsetImageInput = dynamic_cast<mitk::LabelSetImage*>(image);
+    const auto labelsetImageInput = dynamic_cast<mitk::LabelSetImage*>(image);
     if (nullptr != labelsetImageInput)
     {
       cutter->SetInput(labelsetImageInput);
       // do the actual cutting
       try
       {
         cutter->Update();
       }
       catch (const itk::ExceptionObject& e)
       {
         std::string message = std::string("The Cropping filter could not process because of: \n ") + e.GetDescription();
         QMessageBox::warning(nullptr, tr("Cropping not possible!"), tr(message.c_str()),
           QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton);
         return;
       }
 
       auto labelSetImage = mitk::LabelSetImage::New();
       labelSetImage->InitializeByLabeledImage(cutter->GetOutput());
 
       for (unsigned int i = 0; i < labelsetImageInput->GetNumberOfLayers(); i++)
       {
-        labelSetImage->AddLabelSetToLayer(i, labelsetImageInput->GetLabelSet(i));
+        labelSetImage->ReplaceGroupLabels(i, labelsetImageInput->GetConstLabelsInGroup(i));
       }
 
       croppedImageNode->SetData(labelSetImage);
       croppedImageNode->SetProperty("name", mitk::StringProperty::New(imageName.toStdString()));
 
       //add cropping result to the current data storage as child node to the image node
       if (!m_Controls.checkOverwriteImage->isChecked())
       {
         if (!this->GetDataStorage()->Exists(croppedImageNode))
         {
           this->GetDataStorage()->Add(croppedImageNode, imageNode);
         }
       }
       else // original image will be overwritten by the result image and the bounding box of the result is adjusted
       {
         imageNode->SetData(labelSetImage);
         imageNode->Modified();
         // Adjust coordinate system by doing a reinit on
         auto tempDataStorage = mitk::DataStorage::SetOfObjects::New();
         tempDataStorage->InsertElement(0, imageNode);
 
         // initialize the views to the bounding geometry
         auto bounds = this->GetDataStorage()->ComputeBoundingGeometry3D(tempDataStorage);
         mitk::RenderingManager::GetInstance()->InitializeViews(bounds);
       }
     }
     else
     {
       cutter->SetInput(image);
       // do the actual cutting
       try
       {
         cutter->Update();
       }
       catch (const itk::ExceptionObject& e)
       {
         std::string message = std::string("The Cropping filter could not process because of: \n ") + e.GetDescription();
         QMessageBox::warning(nullptr, tr("Cropping not possible!"), tr(message.c_str()),
           QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton);
         return;
       }
 
       //add cropping result to the current data storage as child node to the image node
       if (!m_Controls.checkOverwriteImage->isChecked())
       {
         croppedImageNode->SetData(cutter->GetOutput());
         croppedImageNode->SetProperty("name", mitk::StringProperty::New(imageName.toStdString()));
         croppedImageNode->SetProperty("color", mitk::ColorProperty::New(1.0, 1.0, 1.0));
 
         mitk::LevelWindow levelWindow;
         imageNode->GetLevelWindow(levelWindow);
         croppedImageNode->SetLevelWindow(levelWindow);
 
         if (!this->GetDataStorage()->Exists(croppedImageNode))
         {
           this->GetDataStorage()->Add(croppedImageNode, imageNode);
           imageNode->SetVisibility(mask); // Give the user a visual clue that something happened when image was cropped
         }
       }
       else // original image will be overwritten by the result image and the bounding box of the result is adjusted
       {
         mitk::LevelWindow levelWindow;
         imageNode->GetLevelWindow(levelWindow);
         imageNode->SetData(cutter->GetOutput());
         imageNode->SetLevelWindow(levelWindow);
         // Adjust coordinate system by doing a reinit on
         auto tempDataStorage = mitk::DataStorage::SetOfObjects::New();
         tempDataStorage->InsertElement(0, imageNode);
 
         // initialize the views to the bounding geometry
         auto bounds = this->GetDataStorage()->ComputeBoundingGeometry3D(tempDataStorage);
         mitk::RenderingManager::GetInstance()->InitializeViews(bounds);
       }
     }
   }
   else
   {
     QMessageBox::information(nullptr, "Warning", "Please load and select an image before starting image processing.");
   }
 }
 
 void QmitkImageCropperView::SetDefaultGUI()
 {
   m_Controls.buttonCreateNewBoundingBox->setEnabled(false);
   m_Controls.buttonCropping->setEnabled(false);
   m_Controls.buttonMasking->setEnabled(false);
   m_Controls.buttonAdvancedSettings->setEnabled(false);
   m_Controls.groupImageSettings->setEnabled(false);
   m_Controls.groupImageSettings->setVisible(false);
   m_Controls.checkOverwriteImage->setChecked(false);
   m_Controls.checkBoxCropTimeStepOnly->setChecked(false);
 }
 
 QString QmitkImageCropperView::AdaptBoundingObjectName(const QString& name) const
 {
   unsigned int counter = 2;
   QString newName = QString("%1 %2").arg(name).arg(counter);
 
   while (nullptr != this->GetDataStorage()->GetNode(mitk::NodePredicateFunction::New([&newName](const mitk::DataNode *node)
   {
     return 0 == node->GetName().compare(newName.toStdString());
   })))
   {
     newName = QString("%1 %2").arg(name).arg(++counter);
   }
 
   return newName;
 }