diff --git a/Modules/Segmentation/Algorithms/mitkShowSegmentationAsSurface.cpp b/Modules/Segmentation/Algorithms/mitkShowSegmentationAsSurface.cpp
index ec182eeee7..64efffee41 100644
--- a/Modules/Segmentation/Algorithms/mitkShowSegmentationAsSurface.cpp
+++ b/Modules/Segmentation/Algorithms/mitkShowSegmentationAsSurface.cpp
@@ -1,333 +1,325 @@
 /*============================================================================
 
 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)
     {
       const auto labels = labelSetImage->GetLabels();
 
-      for (decltype(numberOfLayers) layerIndex = 0; layerIndex < numberOfLayers; ++layerIndex)
+      for (auto label : labels)
       {
-        auto labelSet = labelSetImage->GetLabelSet(layerIndex);
+        auto labelImage = labelSetImage->CreateLabelMask(label->GetValue());
 
-        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;
+        if (labelImage.IsNull())
+          continue;
 
-          auto labelSurface = this->ConvertBinaryImageToSurface(labelImage);
+        auto labelSurface = this->ConvertBinaryImageToSurface(labelImage);
 
-          if (labelSurface.IsNull())
-            continue;
+        if (labelSurface.IsNull())
+          continue;
 
-          auto* polyData = labelSurface->GetVtkPolyData();
+        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;
-          }
+        if (smooth && (polyData->GetNumberOfPoints() < 1 || polyData->GetNumberOfCells() < 1))
+        {
+          MITK_WARN << "Label \"" << label->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());
+        auto node = DataNode::New();
+        node->SetData(labelSurface);
+        node->SetColor(label->GetColor());
+        node->SetName(label->GetName());
 
-          m_SurfaceNodes.push_back(node);
-        }
+        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/Modules/Segmentation/cmdapps/ContoursToImage.cpp b/Modules/Segmentation/cmdapps/ContoursToImage.cpp
index d6f865c9fa..8d63fca2b1 100644
--- a/Modules/Segmentation/cmdapps/ContoursToImage.cpp
+++ b/Modules/Segmentation/cmdapps/ContoursToImage.cpp
@@ -1,312 +1,312 @@
 /*============================================================================
 
 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 <mitkCommandLineParser.h>
 #include <mitkContourModelSet.h>
 #include <mitkContourModelSetToImageFilter.h>
 #include <mitkDataStorage.h>
 #include <mitkImageReadAccessor.h>
 #include <mitkImageWriteAccessor.h>
 #include <mitkIOUtil.h>
 #include <mitkLabelSetImage.h>
 #include <mitkLabelSetImageHelper.h>
 
 #include <boost/algorithm/string/trim.hpp>
 #include <boost/algorithm/string/replace.hpp>
 
 #include <filesystem>
 
 enum class OutputFormat
 {
   Binary,
   Label,
   Multilabel
 };
 
 void InitializeCommandLineParser(mitkCommandLineParser& parser)
 {
   parser.setTitle("Contour to Image Converter");
   parser.setCategory("Segmentation");
   parser.setDescription("Converts contours (i. e. RTSTRUCT or MITK Contour Model Set) to binary image masks or (multi-)label segmentations.");
   parser.setContributor("German Cancer Research Center (DKFZ)");
   parser.setArgumentPrefix("--", "-");
 
   parser.addArgument("input", "i", mitkCommandLineParser::File, "Input file:", "Input contour(s)", us::Any(), false, false, false, mitkCommandLineParser::Input);
   parser.addArgument("reference", "r", mitkCommandLineParser::Image, "Reference image:", "Input reference image", us::Any(), false, false, false, mitkCommandLineParser::Input);
   parser.addArgument("output", "o", mitkCommandLineParser::Image, "Output file:", "Output image", us::Any(), false, false, false, mitkCommandLineParser::Output);
   parser.addArgument("format", "f", mitkCommandLineParser::String, "Output format:", "Output format (binary, label, or multilabel)", std::string("binary"));
 }
 
 std::string GetSafeName(const mitk::IPropertyProvider* propertyProvider)
 {
   std::string name;
 
   if (propertyProvider != nullptr)
   {
     name = propertyProvider->GetConstProperty("name")->GetValueAsString();
 
     if (!name.empty())
     {
       boost::trim(name);
       boost::replace_all(name, "/", "_");
       boost::replace_all(name, "\\", "_");
 
       // If you read this, feel free to handle invalid filename characters here. :)
     }
   }
 
   return name;
 }
 
 void CreateParentDirectories(const std::filesystem::path& path)
 {
   if (path.has_parent_path())
   {
     auto parentPath = path.parent_path();
 
     if (!std::filesystem::exists(parentPath))
       std::filesystem::create_directories(parentPath);
   }
 }
 
 bool SetLabelName(const mitk::IPropertyProvider* propertyProvider, mitk::Label* label)
 {
   if (propertyProvider != nullptr)
   {
     if (auto property = propertyProvider->GetConstProperty("name"); property.IsNotNull())
     {
       if (auto nameProperty = dynamic_cast<const mitk::StringProperty*>(property.GetPointer()); nameProperty != nullptr)
       {
         if (auto name = nameProperty->GetValueAsString(); !name.empty())
         {
           label->SetName(name);
           return true;
         }
       }
     }
   }
 
   return false;
 }
 
 bool SetLabelColor(const mitk::IPropertyProvider* propertyProvider, mitk::Label* label)
 {
   if (propertyProvider != nullptr)
   {
     if (auto property = propertyProvider->GetConstProperty("color"); property.IsNotNull())
     {
       if (auto colorProperty = dynamic_cast<const mitk::ColorProperty*>(property.GetPointer()); colorProperty != nullptr)
       {
         label->SetColor(colorProperty->GetColor());
         return true;
       }
     }
   }
 
   return false;
 }
 
 void CopyImageToActiveLayerImage(const mitk::Image* image, mitk::LabelSetImage* labelSetImage)
 {
   mitk::ImageReadAccessor readAccessor(image);
   mitk::ImageWriteAccessor writeAccessor(labelSetImage);
 
   auto size = sizeof(mitk::Label::PixelType);
 
   for (size_t dim = 0; dim < image->GetDimension(); ++dim)
     size *= image->GetDimension(dim);
 
   memcpy(writeAccessor.GetData(), readAccessor.GetData(), size);
 }
 
 OutputFormat ParseOutputFormat(const mitk::IFileIO::Options& args)
 {
   auto it = args.find("format");
 
   if (it != args.end())
   {
     auto format = us::any_cast<std::string>(it->second);
 
     if (format == "multilabel")
       return OutputFormat::Multilabel;
 
     if (format == "label")
       return OutputFormat::Label;
 
     if (format != "binary")
       mitkThrow() << "Unknown output format \"" << format << "\" (must be \"binary\", \"label\" or \"multilabel\").";
   }
 
   return OutputFormat::Binary;
 }
 
 std::vector<mitk::ContourModelSet::Pointer> FilterValidInputs(const std::vector<mitk::BaseData::Pointer>& inputs)
 {
   std::vector<mitk::ContourModelSet::Pointer> validInputs;
 
   for (auto input : inputs)
   {
     if (input.IsNull())
     {
       MITK_WARN << "Skipping null input.";
       continue;
     }
 
     auto* validInput = dynamic_cast<mitk::ContourModelSet*>(input.GetPointer());
 
     if (validInput == nullptr)
     {
       MITK_WARN << "Skipping input of type \"" << input->GetNameOfClass() << "\".";
       continue;
     }
 
     validInputs.push_back(validInput);
   }
 
   return validInputs;
 }
 
 int main(int argc, char* argv[])
 {
   int returnValue = EXIT_SUCCESS;
 
   mitkCommandLineParser parser;
   InitializeCommandLineParser(parser);
 
   auto args = parser.parseArguments(argc, argv);
 
   if (args.empty())
     return EXIT_FAILURE;
 
   try
   {
     auto inputFilename = us::any_cast<std::string>(args["input"]);
     auto referenceFilename = us::any_cast<std::string>(args["reference"]);
     auto outputFilename = us::any_cast<std::string>(args["output"]);
     auto format = ParseOutputFormat(args);
 
     auto referenceImage = mitk::IOUtil::Load<mitk::Image>(referenceFilename);
     auto inputs = FilterValidInputs(mitk::IOUtil::Load(inputFilename));
 
     MITK_INFO << "Found " << inputs.size() << " input contour set(s)";
 
     std::filesystem::path outputPath(outputFilename);
     CreateParentDirectories(outputPath);
 
     mitk::LabelSetImage::Pointer labelSetImage; // Only used for "multilabel" output
     unsigned int nonameCounter = 0; // Helper variable to generate placeholder names for nameless contour sets
 
     for (auto input : inputs)
     {
       // If the input file contains multiple contour sets but the output format is not set to "multilabel",
       // we create separate output files for each contour set. In this case the specified output filename
       // is used only as a base filename and the names of the individual contour sets are appended accordingly.
 
       if (inputs.size() > 1 && format != OutputFormat::Multilabel)
       {
         outputPath = outputFilename;
         auto name = GetSafeName(input);
 
         if (name.empty())
           name = "nameless_" + std::to_string(nonameCounter++);
 
         outputPath.replace_filename(outputPath.stem().string() + '_' + name + outputPath.extension().string());
       }
 
       // Do the actual conversion from a contour set to an image with a background pixel value of 0.
       // - For "binary" output, use pixel value 1 and unsigned char as pixel type.
       // - For "label" output, use pixel value 1 and our label pixel type.
       // - For "multilabel" output, use the next available label value instead.
 
       const auto labelValue = labelSetImage.IsNotNull()
-        ? static_cast<mitk::Label::PixelType>(labelSetImage->GetTotalNumberOfLabels() + 1)
+        ? labelSetImage->GetUnusedLabelValue()
         : 1;
 
       auto filter = mitk::ContourModelSetToImageFilter::New();
       filter->SetMakeOutputLabelPixelType(format != OutputFormat::Binary);
       filter->SetPaintingPixelValue(labelValue);
       filter->SetImage(referenceImage);
       filter->SetInput(input);
 
       filter->Update();
 
       mitk::Image::Pointer image = filter->GetOutput();
       filter = nullptr;
 
       if (image.IsNull())
       {
         MITK_ERROR << "Contour set to image conversion failed without exception. Continue with next contour set... ";
         returnValue = EXIT_FAILURE;
         continue;
       }
 
       if (format == OutputFormat::Binary)
       {
         mitk::IOUtil::Save(image, outputPath.string());
       }
       else
       {
         if (labelSetImage.IsNull())
         {
           labelSetImage = mitk::LabelSetImage::New();
           labelSetImage->Initialize(image);
 
           CopyImageToActiveLayerImage(image, labelSetImage);
         }
         else
         {
           labelSetImage->AddLayer(image);
         }
 
         auto label = mitk::LabelSetImageHelper::CreateNewLabel(labelSetImage);
         label->SetValue(labelValue);
 
         SetLabelName(input, label);
         SetLabelColor(input, label);
 
         if (format == OutputFormat::Multilabel)
           MITK_INFO << "Creating label: " << label->GetName() << " [" << labelValue << ']';
 
-        labelSetImage->GetActiveLabelSet()->AddLabel(label, false);
+        labelSetImage->AddLabel(label, labelSetImage->GetActiveLayer(), false, false);
 
         if (format == OutputFormat::Label)
         {
           mitk::IOUtil::Save(labelSetImage, outputPath.string());
           labelSetImage = nullptr;
         }
       }
     }
 
     // In case of the "multilabel" output format, eventually save the single output file.
     // For all other output formats, the output file(s) have been saved already while iterating
     // over the inputs.
 
     if (labelSetImage.IsNotNull())
       mitk::IOUtil::Save(labelSetImage, outputPath.string());
   }
   catch (const mitk::Exception& e)
   {
     MITK_ERROR << e.GetDescription();
     return EXIT_FAILURE;
   }
   catch (const std::exception& e)
   {
     MITK_ERROR << e.what();
     return EXIT_FAILURE;
   }
   catch (...)
   {
     return EXIT_FAILURE;
   }
 
   return returnValue;
 }