diff --git a/Modules/Segmentation/Algorithms/mitkShapeBasedInterpolationAlgorithm.cpp b/Modules/Segmentation/Algorithms/mitkShapeBasedInterpolationAlgorithm.cpp
index 4299326227..a88a329469 100644
--- a/Modules/Segmentation/Algorithms/mitkShapeBasedInterpolationAlgorithm.cpp
+++ b/Modules/Segmentation/Algorithms/mitkShapeBasedInterpolationAlgorithm.cpp
@@ -1,151 +1,157 @@
 /*============================================================================
 
 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 "mitkShapeBasedInterpolationAlgorithm.h"
 #include "mitkImageAccessByItk.h"
 #include "mitkImageCast.h"
 #include <mitkITKImageImport.h>
 
 #include <itkFastChamferDistanceImageFilter.h>
 #include <itkInvertIntensityImageFilter.h>
 #include <itkIsoContourDistanceImageFilter.h>
 #include <itkSubtractImageFilter.h>
 
 #include <thread>
 
 mitk::Image::Pointer mitk::ShapeBasedInterpolationAlgorithm::Interpolate(
   Image::ConstPointer lowerSlice,
   unsigned int lowerSliceIndex,
   Image::ConstPointer upperSlice,
   unsigned int upperSliceIndex,
   unsigned int requestedIndex,
   unsigned int /*sliceDimension*/, // commented variables are not used
   Image::Pointer resultImage,
   unsigned int /*timeStep*/,
   Image::ConstPointer /*referenceImage*/)
 {
   auto lowerDistanceImage = this->ComputeDistanceMap(lowerSliceIndex, lowerSlice);
   auto upperDistanceImage = this->ComputeDistanceMap(upperSliceIndex, upperSlice);
 
   // calculate where the current slice is in comparison to the lower and upper neighboring slices
   float ratio = (float)(requestedIndex - lowerSliceIndex) / (float)(upperSliceIndex - lowerSliceIndex);
   AccessFixedDimensionByItk_3(resultImage, InterpolateIntermediateSlice, 2, upperDistanceImage, lowerDistanceImage, ratio);
 
   return resultImage;
 }
 
 mitk::Image::Pointer mitk::ShapeBasedInterpolationAlgorithm::ComputeDistanceMap(unsigned int sliceIndex, Image::ConstPointer slice)
 {
   static const auto MAX_CACHE_SIZE = 2 * std::thread::hardware_concurrency();
 
-  if (0 != m_DistanceImageCache.count(sliceIndex))
-    return m_DistanceImageCache[sliceIndex];
+  {
+    std::lock_guard<std::mutex> lock(m_DistanceImageCacheMutex);
+
+    if (0 != m_DistanceImageCache.count(sliceIndex))
+      return m_DistanceImageCache[sliceIndex];
 
-  if (MAX_CACHE_SIZE < m_DistanceImageCache.size())
-    m_DistanceImageCache.clear();
+    if (MAX_CACHE_SIZE < m_DistanceImageCache.size())
+      m_DistanceImageCache.clear();
+  }
 
   auto distanceImage = mitk::Image::New();
   AccessFixedDimensionByItk_1(slice, ComputeDistanceMap, 2, distanceImage);
 
+  std::lock_guard<std::mutex> lock(m_DistanceImageCacheMutex);
+
   m_DistanceImageCache[sliceIndex] = distanceImage;
 
   return distanceImage;
 }
 
 template <typename TPixel, unsigned int VImageDimension>
 void mitk::ShapeBasedInterpolationAlgorithm::ComputeDistanceMap(const itk::Image<TPixel, VImageDimension> *binaryImage,
                                                                 mitk::Image::Pointer &result)
 {
   typedef itk::Image<TPixel, VImageDimension> DistanceFilterInputImageType;
 
   typedef itk::FastChamferDistanceImageFilter<DistanceFilterImageType, DistanceFilterImageType> DistanceFilterType;
   typedef itk::IsoContourDistanceImageFilter<DistanceFilterInputImageType, DistanceFilterImageType> IsoContourType;
   typedef itk::InvertIntensityImageFilter<DistanceFilterInputImageType> InvertIntensityImageFilterType;
   typedef itk::SubtractImageFilter<DistanceFilterImageType, DistanceFilterImageType> SubtractImageFilterType;
 
   typename DistanceFilterType::Pointer distanceFilter = DistanceFilterType::New();
   typename DistanceFilterType::Pointer distanceFilterInverted = DistanceFilterType::New();
   typename IsoContourType::Pointer isoContourFilter = IsoContourType::New();
   typename IsoContourType::Pointer isoContourFilterInverted = IsoContourType::New();
   typename InvertIntensityImageFilterType::Pointer invertFilter = InvertIntensityImageFilterType::New();
   typename SubtractImageFilterType::Pointer subtractImageFilter = SubtractImageFilterType::New();
 
   // arbitrary maximum distance
   int maximumDistance = 100;
 
   // this assumes the image contains only 1 and 0
   invertFilter->SetInput(binaryImage);
   invertFilter->SetMaximum(1);
 
   // do the processing on the image and the inverted image to get inside and outside distance
   isoContourFilter->SetInput(binaryImage);
   isoContourFilter->SetFarValue(maximumDistance + 1);
   isoContourFilter->SetLevelSetValue(0);
 
   isoContourFilterInverted->SetInput(invertFilter->GetOutput());
   isoContourFilterInverted->SetFarValue(maximumDistance + 1);
   isoContourFilterInverted->SetLevelSetValue(0);
 
   distanceFilter->SetInput(isoContourFilter->GetOutput());
   distanceFilter->SetMaximumDistance(maximumDistance);
 
   distanceFilterInverted->SetInput(isoContourFilterInverted->GetOutput());
   distanceFilterInverted->SetMaximumDistance(maximumDistance);
 
   // inside distance should be negative, outside distance positive
   subtractImageFilter->SetInput2(distanceFilter->GetOutput());
   subtractImageFilter->SetInput1(distanceFilterInverted->GetOutput());
   subtractImageFilter->Update();
 
   result = mitk::GrabItkImageMemory(subtractImageFilter->GetOutput());
 }
 
 template <typename TPixel, unsigned int VImageDimension>
 void mitk::ShapeBasedInterpolationAlgorithm::InterpolateIntermediateSlice(itk::Image<TPixel, VImageDimension> *result,
                                                                           const mitk::Image::Pointer &lower,
                                                                           const mitk::Image::Pointer &upper,
                                                                           float ratio)
 {
   typename DistanceFilterImageType::Pointer lowerITK = DistanceFilterImageType::New();
   typename DistanceFilterImageType::Pointer upperITK = DistanceFilterImageType::New();
 
   CastToItkImage(lower, lowerITK);
   CastToItkImage(upper, upperITK);
 
   itk::ImageRegionConstIteratorWithIndex<DistanceFilterImageType> lowerIter(lowerITK,
                                                                             lowerITK->GetLargestPossibleRegion());
 
   lowerIter.GoToBegin();
 
   if (!lowerITK->GetLargestPossibleRegion().IsInside(upperITK->GetLargestPossibleRegion()) ||
       !lowerITK->GetLargestPossibleRegion().IsInside(result->GetLargestPossibleRegion()))
   {
     // TODO Exception etc.
     MITK_ERROR << "The regions of the slices for the 2D interpolation are not equally sized!";
     return;
   }
 
   float weight[2] = {1.0f - ratio, ratio};
 
   while (!lowerIter.IsAtEnd())
   {
     typename DistanceFilterImageType::PixelType lowerPixelVal = lowerIter.Get();
     typename DistanceFilterImageType::PixelType upperPixelVal = upperITK->GetPixel(lowerIter.GetIndex());
 
     typename DistanceFilterImageType::PixelType intermediatePixelVal =
       (weight[0] * upperPixelVal + weight[1] * lowerPixelVal > 0 ? 0 : 1);
 
     result->SetPixel(lowerIter.GetIndex(), static_cast<TPixel>(intermediatePixelVal));
 
     ++lowerIter;
   }
 }
diff --git a/Modules/Segmentation/Algorithms/mitkShapeBasedInterpolationAlgorithm.h b/Modules/Segmentation/Algorithms/mitkShapeBasedInterpolationAlgorithm.h
index 92f44810b9..1ba28195f6 100644
--- a/Modules/Segmentation/Algorithms/mitkShapeBasedInterpolationAlgorithm.h
+++ b/Modules/Segmentation/Algorithms/mitkShapeBasedInterpolationAlgorithm.h
@@ -1,71 +1,73 @@
 /*============================================================================
 
 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 mitkShapeBasedInterpolationAlgorithm_h_Included
 #define mitkShapeBasedInterpolationAlgorithm_h_Included
 
 #include "mitkSegmentationInterpolationAlgorithm.h"
 #include <MitkSegmentationExports.h>
 
 #include <map>
+#include <mutex>
 
 namespace mitk
 {
   /**
    * \brief Shape-based binary image interpolation.
    *
    * This class uses legacy code from ipSegmentation to implement
    * the shape-based interpolation algorithm described in
    *
    * G.T. Herman, J. Zheng, C.A. Bucholtz: "Shape-based interpolation"
    * IEEE Computer Graphics & Applications, pp. 69-79,May 1992
    *
    *  Last contributor:
    *  $Author:$
    */
   class MITKSEGMENTATION_EXPORT ShapeBasedInterpolationAlgorithm : public SegmentationInterpolationAlgorithm
   {
   public:
     mitkClassMacro(ShapeBasedInterpolationAlgorithm, SegmentationInterpolationAlgorithm);
     itkFactorylessNewMacro(Self);
     itkCloneMacro(Self);
 
       Image::Pointer Interpolate(Image::ConstPointer lowerSlice,
                                  unsigned int lowerSliceIndex,
                                  Image::ConstPointer upperSlice,
                                  unsigned int upperSliceIndex,
                                  unsigned int requestedIndex,
                                  unsigned int sliceDimension,
                                  Image::Pointer resultImage,
                                  unsigned int timeStep,
                                  Image::ConstPointer referenceImage) override;
 
   private:
     typedef itk::Image<mitk::ScalarType, 2> DistanceFilterImageType;
 
     template <typename TPixel, unsigned int VImageDimension>
     void ComputeDistanceMap(const itk::Image<TPixel, VImageDimension> *, mitk::Image::Pointer &result);
 
     Image::Pointer ComputeDistanceMap(unsigned int sliceIndex, Image::ConstPointer slice);
 
     template <typename TPixel, unsigned int VImageDimension>
     void InterpolateIntermediateSlice(itk::Image<TPixel, VImageDimension> *result,
                                       const mitk::Image::Pointer &lowerDistanceImage,
                                       const mitk::Image::Pointer &upperDistanceImage,
                                       float ratio);
 
     std::map<unsigned int, Image::Pointer> m_DistanceImageCache;
+    std::mutex m_DistanceImageCacheMutex;
   };
 
 } // namespace
 
 #endif
diff --git a/Modules/Segmentation/Controllers/mitkSegmentationInterpolationController.cpp b/Modules/Segmentation/Controllers/mitkSegmentationInterpolationController.cpp
index 14c9d6a70d..43c802b2d8 100644
--- a/Modules/Segmentation/Controllers/mitkSegmentationInterpolationController.cpp
+++ b/Modules/Segmentation/Controllers/mitkSegmentationInterpolationController.cpp
@@ -1,599 +1,604 @@
 /*============================================================================
 
 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 "mitkSegmentationInterpolationController.h"
 
 #include "mitkImageCast.h"
 #include "mitkImageReadAccessor.h"
 #include "mitkImageTimeSelector.h"
 #include <mitkExtractSliceFilter.h>
 #include <mitkImageAccessByItk.h>
 //#include <mitkPlaneGeometry.h>
 
 #include "mitkShapeBasedInterpolationAlgorithm.h"
 
 #include <itkCommand.h>
 #include <itkImage.h>
 #include <itkImageSliceConstIteratorWithIndex.h>
 
 #include <thread>
 
 mitk::SegmentationInterpolationController::InterpolatorMapType
   mitk::SegmentationInterpolationController::s_InterpolatorForImage; // static member initialization
 
 mitk::SegmentationInterpolationController *mitk::SegmentationInterpolationController::InterpolatorForImage(
   const Image *image)
 {
   auto iter = s_InterpolatorForImage.find(image);
   if (iter != s_InterpolatorForImage.end())
   {
     return iter->second;
   }
   else
   {
     return nullptr;
   }
 }
 
 mitk::SegmentationInterpolationController::SegmentationInterpolationController()
   : m_BlockModified(false), m_2DInterpolationActivated(false), m_EnableSliceImageCache(false)
 {
 }
 
 void mitk::SegmentationInterpolationController::Activate2DInterpolation(bool status)
 {
   m_2DInterpolationActivated = status;
 }
 
 mitk::SegmentationInterpolationController *mitk::SegmentationInterpolationController::GetInstance()
 {
   static mitk::SegmentationInterpolationController::Pointer m_Instance;
 
   if (m_Instance.IsNull())
   {
     m_Instance = SegmentationInterpolationController::New();
   }
   return m_Instance;
 }
 
 mitk::SegmentationInterpolationController::~SegmentationInterpolationController()
 {
   // remove this from the list of interpolators
   for (auto iter = s_InterpolatorForImage.begin(); iter != s_InterpolatorForImage.end(); ++iter)
   {
     if (iter->second == this)
     {
       s_InterpolatorForImage.erase(iter);
       break;
     }
   }
 }
 
 void mitk::SegmentationInterpolationController::OnImageModified(const itk::EventObject &)
 {
   if (!m_BlockModified && m_Segmentation.IsNotNull() && m_2DInterpolationActivated)
   {
     SetSegmentationVolume(m_Segmentation);
   }
 }
 
 void mitk::SegmentationInterpolationController::BlockModified(bool block)
 {
   m_BlockModified = block;
 }
 
 void mitk::SegmentationInterpolationController::SetSegmentationVolume(const Image *segmentation)
 {
   // clear old information (remove all time steps
   m_SegmentationCountInSlice.clear();
 
   // delete this from the list of interpolators
   auto iter = s_InterpolatorForImage.find(segmentation);
   if (iter != s_InterpolatorForImage.end())
   {
     s_InterpolatorForImage.erase(iter);
   }
 
   if (!segmentation)
     return;
   if (segmentation->GetDimension() > 4 || segmentation->GetDimension() < 3)
   {
     itkExceptionMacro("SegmentationInterpolationController needs a 3D-segmentation or 3D+t, not 2D.");
   }
 
   if (m_Segmentation != segmentation)
   {
     // observe Modified() event of image
     itk::ReceptorMemberCommand<SegmentationInterpolationController>::Pointer command =
       itk::ReceptorMemberCommand<SegmentationInterpolationController>::New();
     command->SetCallbackFunction(this, &SegmentationInterpolationController::OnImageModified);
     segmentation->AddObserver(itk::ModifiedEvent(), command);
   }
 
   m_Segmentation = segmentation;
 
   m_SegmentationCountInSlice.resize(m_Segmentation->GetTimeSteps());
   for (unsigned int timeStep = 0; timeStep < m_Segmentation->GetTimeSteps(); ++timeStep)
   {
     m_SegmentationCountInSlice[timeStep].resize(3);
     for (unsigned int dim = 0; dim < 3; ++dim)
     {
       m_SegmentationCountInSlice[timeStep][dim].clear();
       m_SegmentationCountInSlice[timeStep][dim].resize(m_Segmentation->GetDimension(dim));
       m_SegmentationCountInSlice[timeStep][dim].assign(m_Segmentation->GetDimension(dim), 0);
     }
   }
 
   s_InterpolatorForImage.insert(std::make_pair(m_Segmentation, this));
 
   // for all timesteps
   // scan whole image
   for (unsigned int timeStep = 0; timeStep < m_Segmentation->GetTimeSteps(); ++timeStep)
   {
     ImageTimeSelector::Pointer timeSelector = ImageTimeSelector::New();
     timeSelector->SetInput(m_Segmentation);
     timeSelector->SetTimeNr(timeStep);
     timeSelector->UpdateLargestPossibleRegion();
     Image::Pointer segmentation3D = timeSelector->GetOutput();
     AccessFixedDimensionByItk_2(segmentation3D, ScanWholeVolume, 3, m_Segmentation, timeStep);
   }
 
   // PrintStatus();
 
   SetReferenceVolume(m_ReferenceImage);
 
   Modified();
 }
 
 void mitk::SegmentationInterpolationController::SetReferenceVolume(const Image *referenceImage)
 {
   m_ReferenceImage = referenceImage;
 
   if (m_ReferenceImage.IsNull())
     return;                           // no image set - ignore it then
   assert(m_Segmentation.IsNotNull()); // should never happen
 
   // ensure the reference image has the same dimensionality and extents as the segmentation image
   if (m_ReferenceImage.IsNull() || m_Segmentation.IsNull() ||
       m_ReferenceImage->GetDimension() != m_Segmentation->GetDimension() ||
       m_ReferenceImage->GetPixelType().GetNumberOfComponents() != 1 ||
       m_Segmentation->GetPixelType().GetNumberOfComponents() != 1)
   {
     MITK_WARN << "Segmentation image has different image characteristics than reference image." << std::endl;
     m_ReferenceImage = nullptr;
     return;
   }
 
   for (unsigned int dim = 0; dim < m_Segmentation->GetDimension(); ++dim)
     if (m_ReferenceImage->GetDimension(dim) != m_Segmentation->GetDimension(dim))
     {
       MITK_WARN << "original patient image does not match segmentation (different extent in dimension " << dim
                 << "), ignoring patient image" << std::endl;
       m_ReferenceImage = nullptr;
       return;
     }
 }
 
 void mitk::SegmentationInterpolationController::SetChangedVolume(const Image *sliceDiff, unsigned int timeStep)
 {
   if (!sliceDiff)
     return;
   if (sliceDiff->GetDimension() != 3)
     return;
 
   AccessFixedDimensionByItk_1(sliceDiff, ScanChangedVolume, 3, timeStep);
 
   // PrintStatus();
   Modified();
 }
 
 void mitk::SegmentationInterpolationController::SetChangedSlice(const Image *sliceDiff,
                                                                 unsigned int sliceDimension,
                                                                 unsigned int sliceIndex,
                                                                 unsigned int timeStep)
 {
   if (!sliceDiff)
     return;
   if (sliceDimension > 2)
     return;
   if (timeStep >= m_SegmentationCountInSlice.size())
     return;
   if (sliceIndex >= m_SegmentationCountInSlice[timeStep][sliceDimension].size())
     return;
 
   unsigned int dim0(0);
   unsigned int dim1(1);
 
   // determine the other two dimensions
   switch (sliceDimension)
   {
     default:
     case 2:
       dim0 = 0;
       dim1 = 1;
       break;
     case 1:
       dim0 = 0;
       dim1 = 2;
       break;
     case 0:
       dim0 = 1;
       dim1 = 2;
       break;
   }
 
   mitk::ImageReadAccessor readAccess(sliceDiff);
   auto *rawSlice = (unsigned char *)readAccess.GetData();
   if (!rawSlice)
     return;
 
   AccessFixedDimensionByItk_1(
     sliceDiff, ScanChangedSlice, 2, SetChangedSliceOptions(sliceDimension, sliceIndex, dim0, dim1, timeStep, rawSlice));
 
   Modified();
 }
 
 template <typename DATATYPE>
 void mitk::SegmentationInterpolationController::ScanChangedSlice(const itk::Image<DATATYPE, 2> *,
                                                                  const SetChangedSliceOptions &options)
 {
   auto *pixelData((DATATYPE *)options.pixelData);
 
   unsigned int timeStep(options.timeStep);
 
   unsigned int sliceDimension(options.sliceDimension);
   unsigned int sliceIndex(options.sliceIndex);
 
   if (sliceDimension > 2)
     return;
   if (sliceIndex >= m_SegmentationCountInSlice[timeStep][sliceDimension].size())
     return;
 
   unsigned int dim0(options.dim0);
   unsigned int dim1(options.dim1);
 
   int numberOfPixels(0); // number of pixels in this slice that are not 0
 
   unsigned int dim0max = m_SegmentationCountInSlice[timeStep][dim0].size();
   unsigned int dim1max = m_SegmentationCountInSlice[timeStep][dim1].size();
 
   // scan the slice from two directions
   // and set the flags for the two dimensions of the slice
   for (unsigned int v = 0; v < dim1max; ++v)
   {
     for (unsigned int u = 0; u < dim0max; ++u)
     {
       DATATYPE value = *(pixelData + u + v * dim0max);
 
       assert((signed)m_SegmentationCountInSlice[timeStep][dim0][u] + (signed)value >=
              0); // just for debugging. This must always be true, otherwise some counting is going wrong
       assert((signed)m_SegmentationCountInSlice[timeStep][dim1][v] + (signed)value >= 0);
 
       m_SegmentationCountInSlice[timeStep][dim0][u] =
         static_cast<unsigned int>(m_SegmentationCountInSlice[timeStep][dim0][u] + value);
       m_SegmentationCountInSlice[timeStep][dim1][v] =
         static_cast<unsigned int>(m_SegmentationCountInSlice[timeStep][dim1][v] + value);
       numberOfPixels += static_cast<int>(value);
     }
   }
 
   // flag for the dimension of the slice itself
   assert((signed)m_SegmentationCountInSlice[timeStep][sliceDimension][sliceIndex] + numberOfPixels >= 0);
   m_SegmentationCountInSlice[timeStep][sliceDimension][sliceIndex] += numberOfPixels;
 
   // MITK_INFO << "scan t=" << timeStep << " from (0,0) to (" << dim0max << "," << dim1max << ") (" << pixelData << "-"
   // << pixelData+dim0max*dim1max-1 <<  ") in slice " << sliceIndex << " found " << numberOfPixels << " pixels" <<
   // std::endl;
 }
 
 template <typename TPixel, unsigned int VImageDimension>
 void mitk::SegmentationInterpolationController::ScanChangedVolume(const itk::Image<TPixel, VImageDimension> *diffImage,
                                                                   unsigned int timeStep)
 {
   typedef itk::ImageSliceConstIteratorWithIndex<itk::Image<TPixel, VImageDimension>> IteratorType;
 
   IteratorType iter(diffImage, diffImage->GetLargestPossibleRegion());
   iter.SetFirstDirection(0);
   iter.SetSecondDirection(1);
 
   int numberOfPixels(0); // number of pixels in this slice that are not 0
 
   typename IteratorType::IndexType index;
   unsigned int x = 0;
   unsigned int y = 0;
   unsigned int z = 0;
 
   iter.GoToBegin();
   while (!iter.IsAtEnd())
   {
     while (!iter.IsAtEndOfSlice())
     {
       while (!iter.IsAtEndOfLine())
       {
         index = iter.GetIndex();
 
         x = index[0];
         y = index[1];
         z = index[2];
 
         TPixel value = iter.Get();
 
         assert((signed)m_SegmentationCountInSlice[timeStep][0][x] + (signed)value >=
                0); // just for debugging. This must always be true, otherwise some counting is going wrong
         assert((signed)m_SegmentationCountInSlice[timeStep][1][y] + (signed)value >= 0);
 
         m_SegmentationCountInSlice[timeStep][0][x] =
           static_cast<unsigned int>(m_SegmentationCountInSlice[timeStep][0][x] + value);
         m_SegmentationCountInSlice[timeStep][1][y] =
           static_cast<unsigned int>(m_SegmentationCountInSlice[timeStep][1][y] + value);
 
         numberOfPixels += static_cast<int>(value);
 
         ++iter;
       }
       iter.NextLine();
     }
     assert((signed)m_SegmentationCountInSlice[timeStep][2][z] + numberOfPixels >= 0);
     m_SegmentationCountInSlice[timeStep][2][z] += numberOfPixels;
     numberOfPixels = 0;
 
     iter.NextSlice();
   }
 }
 
 template <typename DATATYPE>
 void mitk::SegmentationInterpolationController::ScanWholeVolume(const itk::Image<DATATYPE, 3> *,
                                                                 const Image *volume,
                                                                 unsigned int timeStep)
 {
   if (!volume)
     return;
   if (timeStep >= m_SegmentationCountInSlice.size())
     return;
 
   ImageReadAccessor readAccess(volume, volume->GetVolumeData(timeStep));
 
   for (unsigned int slice = 0; slice < volume->GetDimension(2); ++slice)
   {
     const auto *rawVolume =
       static_cast<const DATATYPE *>(readAccess.GetData()); // we again promise not to change anything, we'll just count
     const DATATYPE *rawSlice = rawVolume + (volume->GetDimension(0) * volume->GetDimension(1) * slice);
 
     ScanChangedSlice<DATATYPE>(nullptr, SetChangedSliceOptions(2, slice, 0, 1, timeStep, rawSlice));
   }
 }
 
 void mitk::SegmentationInterpolationController::PrintStatus()
 {
   unsigned int timeStep(0); // if needed, put a loop over time steps around everyting, but beware, output will be long
 
   MITK_INFO << "Interpolator status (timestep 0): dimensions " << m_SegmentationCountInSlice[timeStep][0].size() << " "
             << m_SegmentationCountInSlice[timeStep][1].size() << " " << m_SegmentationCountInSlice[timeStep][2].size()
             << std::endl;
 
   MITK_INFO << "Slice 0: " << m_SegmentationCountInSlice[timeStep][2][0] << std::endl;
 
   // row "x"
   for (unsigned int index = 0; index < m_SegmentationCountInSlice[timeStep][0].size(); ++index)
   {
     if (m_SegmentationCountInSlice[timeStep][0][index] > 0)
       MITK_INFO << "O";
     else
       MITK_INFO << ".";
   }
   MITK_INFO << std::endl;
 
   // rows "y" and "z" (diagonal)
   for (unsigned int index = 1; index < m_SegmentationCountInSlice[timeStep][1].size(); ++index)
   {
     if (m_SegmentationCountInSlice[timeStep][1][index] > 0)
       MITK_INFO << "O";
     else
       MITK_INFO << ".";
 
     if (m_SegmentationCountInSlice[timeStep][2].size() > index) // if we also have a z value here, then print it, too
     {
       for (unsigned int indent = 1; indent < index; ++indent)
         MITK_INFO << " ";
 
       if (m_SegmentationCountInSlice[timeStep][2][index] > 0)
         MITK_INFO << m_SegmentationCountInSlice[timeStep][2][index]; //"O";
       else
         MITK_INFO << ".";
     }
 
     MITK_INFO << std::endl;
   }
 
   // z indices that are larger than the biggest y index
   for (unsigned int index = m_SegmentationCountInSlice[timeStep][1].size();
        index < m_SegmentationCountInSlice[timeStep][2].size();
        ++index)
   {
     for (unsigned int indent = 0; indent < index; ++indent)
       MITK_INFO << " ";
 
     if (m_SegmentationCountInSlice[timeStep][2][index] > 0)
       MITK_INFO << m_SegmentationCountInSlice[timeStep][2][index]; //"O";
     else
       MITK_INFO << ".";
 
     MITK_INFO << std::endl;
   }
 }
 
 mitk::Image::Pointer mitk::SegmentationInterpolationController::Interpolate(unsigned int sliceDimension,
                                                                             unsigned int sliceIndex,
                                                                             const mitk::PlaneGeometry *currentPlane,
                                                                             unsigned int timeStep,
                                                                             ShapeBasedInterpolationAlgorithm::Pointer algorithm)
 {
   if (m_Segmentation.IsNull() || nullptr == currentPlane)
     return nullptr;
 
   if (timeStep >= m_SegmentationCountInSlice.size())
     return nullptr;
 
   if (sliceDimension > 2)
     return nullptr;
 
   if (0 == sliceIndex)
     return nullptr; // First slice, nothing to interpolate
 
   const unsigned int lastSliceIndex = m_SegmentationCountInSlice[timeStep][sliceDimension].size() - 1;
 
   if (lastSliceIndex <= sliceIndex)
     return nullptr; // Last slice, nothing to interpolate
 
   if (m_SegmentationCountInSlice[timeStep][sliceDimension][sliceIndex] > 0)
     return nullptr; // Slice contains segmentation, nothing to interopolate
 
   unsigned int lowerBound = 0;
   unsigned int upperBound = 0;
   bool bounds = false;
 
   for (lowerBound = sliceIndex - 1; ; --lowerBound)
   {
     if (m_SegmentationCountInSlice[timeStep][sliceDimension][lowerBound] > 0)
     {
       bounds = true;
       break;
     }
 
     if (0 == lowerBound)
       break;
   }
 
   if (!bounds)
     return nullptr;
 
   bounds = false;
 
   for (upperBound = sliceIndex + 1; upperBound <= lastSliceIndex; ++upperBound)
   {
     if (m_SegmentationCountInSlice[timeStep][sliceDimension][upperBound] > 0)
     {
       bounds = true;
       break;
     }
   }
 
   if (!bounds)
     return nullptr;
 
   // We have found two neighboring slices with segmentations and made sure that the current slice does not contain anything
 
   mitk::Image::Pointer lowerSlice;
   mitk::Image::Pointer upperSlice;
   mitk::Image::Pointer resultImage;
 
   try
   {
     // Extract current slice
     resultImage = this->ExtractSlice(currentPlane, sliceIndex, timeStep);
 
     // Creating PlaneGeometry for lower slice
     auto reslicePlane = currentPlane->Clone();
 
     // Transforming the current origin so that it matches the lower slice
     auto origin = currentPlane->GetOrigin();
     m_Segmentation->GetSlicedGeometry(timeStep)->WorldToIndex(origin, origin);
     origin[sliceDimension] = lowerBound;
     m_Segmentation->GetSlicedGeometry(timeStep)->IndexToWorld(origin, origin);
     reslicePlane->SetOrigin(origin);
 
     // Extract lower slice
     lowerSlice = this->ExtractSlice(reslicePlane, lowerBound, timeStep, true);
 
     if (lowerSlice.IsNull())
       return nullptr;
 
     // Transforming the current origin so that it matches the upper slice
     m_Segmentation->GetSlicedGeometry(timeStep)->WorldToIndex(origin, origin);
     origin[sliceDimension] = upperBound;
     m_Segmentation->GetSlicedGeometry(timeStep)->IndexToWorld(origin, origin);
     reslicePlane->SetOrigin(origin);
 
     // Extract the upper slice
     upperSlice = this->ExtractSlice(reslicePlane, upperBound, timeStep, true);
 
     if (upperSlice.IsNull())
       return nullptr;
   }
   catch (const std::exception &e)
   {
     MITK_ERROR << "Error in 2D interpolation: " << e.what();
     return nullptr;
   }
 
   // Interpolation algorithm inputs:
   //   - Two segmentations (guaranteed to be of the same data type)
   //   - Orientation of the segmentations (sliceDimension)
   //   - Position of the two slices (sliceIndices)
   //   - Reference image
   //
   // The interpolation algorithm can use e.g. itk::ImageSliceConstIteratorWithIndex to
   // inspect the reference image at appropriate positions.
 
   if (algorithm.IsNull())
     algorithm = mitk::ShapeBasedInterpolationAlgorithm::New();
 
   return algorithm->Interpolate(
     lowerSlice.GetPointer(),
     lowerBound,
     upperSlice.GetPointer(),
     upperBound,
     sliceIndex,
     sliceDimension,
     resultImage,
     timeStep,
     m_ReferenceImage);
 }
 
 mitk::Image::Pointer mitk::SegmentationInterpolationController::ExtractSlice(const PlaneGeometry* planeGeometry, unsigned int sliceIndex, unsigned int timeStep, bool cache)
 {
   static const auto MAX_CACHE_SIZE = 2 * std::thread::hardware_concurrency();
   const auto key = std::make_pair(sliceIndex, timeStep);
 
   if (cache && m_EnableSliceImageCache)
   {
+    std::lock_guard<std::mutex> lock(m_SliceImageCacheMutex);
+
     if (0 != m_SliceImageCache.count(key))
       return m_SliceImageCache[key];
 
     if (MAX_CACHE_SIZE < m_SliceImageCache.size())
       m_SliceImageCache.clear();
   }
 
   auto extractor = ExtractSliceFilter::New();
   extractor->SetInput(m_Segmentation);
   extractor->SetTimeStep(timeStep);
   extractor->SetResliceTransformByGeometry(m_Segmentation->GetTimeGeometry()->GetGeometryForTimeStep(timeStep));
   extractor->SetVtkOutputRequest(false);
   extractor->SetWorldGeometry(planeGeometry);
   extractor->Update();
 
   if (cache && m_EnableSliceImageCache)
+  {
+    std::lock_guard<std::mutex> lock(m_SliceImageCacheMutex);
     m_SliceImageCache[key] = extractor->GetOutput();
+  }
 
   return extractor->GetOutput();
 }
 
 void mitk::SegmentationInterpolationController::EnableSliceImageCache()
 {
   m_EnableSliceImageCache = true;
 }
 
 void mitk::SegmentationInterpolationController::DisableSliceImageCache()
 {
   m_EnableSliceImageCache = false;
   m_SliceImageCache.clear();
 }
diff --git a/Modules/Segmentation/Controllers/mitkSegmentationInterpolationController.h b/Modules/Segmentation/Controllers/mitkSegmentationInterpolationController.h
index 051a398cb6..9f5c16c4d0 100644
--- a/Modules/Segmentation/Controllers/mitkSegmentationInterpolationController.h
+++ b/Modules/Segmentation/Controllers/mitkSegmentationInterpolationController.h
@@ -1,240 +1,242 @@
 /*============================================================================
 
 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 mitkSegmentationInterpolationController_h_Included
 #define mitkSegmentationInterpolationController_h_Included
 
 #include "mitkCommon.h"
 #include "mitkImage.h"
 #include <MitkSegmentationExports.h>
 
 #include <itkImage.h>
 #include <itkObjectFactory.h>
 
 #include <map>
+#include <mutex>
 #include <utility>
 #include <vector>
 
 namespace mitk
 {
   class Image;
   class ShapeBasedInterpolationAlgorithm;
 
   /**
     \brief Generates interpolations of 2D slices.
 
     \sa QmitkSlicesInterpolator
     \sa QmitkInteractiveSegmentation
 
     \ingroup ToolManagerEtAl
 
     This class keeps track of the contents of a 3D segmentation image.
     \attention mitk::SegmentationInterpolationController assumes that the image contains pixel values of 0 and 1.
 
     After you set the segmentation image using SetSegmentationVolume(), the whole image is scanned for pixels other than
     0.
     SegmentationInterpolationController registers as an observer to the segmentation image, and repeats the scan
     whenvever the
     image is modified.
 
     You can prevent this (time consuming) scan if you do the changes slice-wise and send difference images to
     SegmentationInterpolationController.
     For this purpose SetChangedSlice() should be used. mitk::OverwriteImageFilter already does this every time it
     changes a
     slice of an image. There is a static method InterpolatorForImage(), which can be used to find out if there already
     is an interpolator
     instance for a specified image. OverwriteImageFilter uses this to get to know its interpolator.
 
     SegmentationInterpolationController needs to maintain some information about the image slices (in every dimension).
     This information is stored internally in m_SegmentationCountInSlice, which is basically three std::vectors (one for
     each dimension).
     Each item describes one image dimension, each vector item holds the count of pixels in "its" slice.
 
     $Author$
   */
   class MITKSEGMENTATION_EXPORT SegmentationInterpolationController : public itk::Object
   {
   public:
     mitkClassMacroItkParent(SegmentationInterpolationController, itk::Object);
     itkFactorylessNewMacro(Self);
     itkCloneMacro(Self);
 
       /**
         \brief Find interpolator for a given image.
         \return nullptr if there is no interpolator yet.
 
         This method is useful if several "clients" modify the same image and want to access the interpolations.
         Then they can share the same object.
        */
       static SegmentationInterpolationController *InterpolatorForImage(const Image *);
 
     /**
       \brief Block reaction to an images Modified() events.
 
       Blocking the scan of the whole image is especially useful when you are about to change a single slice
       of the image. Then you would send a difference image of this single slice to SegmentationInterpolationController
       but call image->Modified() anyway. Before calling image->Modified() you should block
       SegmentationInterpolationController's reactions to this modified by using this method.
     */
     void BlockModified(bool);
 
     /**
       \brief Initialize with a whole volume.
 
       Will scan the volume for segmentation pixels (values other than 0) and fill some internal data structures.
       You don't have to call this method every time something changes, but only
       when several slices at once change.
 
       When you change a single slice, call SetChangedSlice() instead.
     */
     void SetSegmentationVolume(const Image *segmentation);
 
     /**
       \brief Set a reference image (original patient image) - optional.
 
       If this volume is set (must exactly match the dimensions of the segmentation),
       the interpolation algorithm may consider image content to improve the interpolated
       (estimated) segmentation.
      */
     void SetReferenceVolume(const Image *segmentation);
 
     /**
       \brief Update after changing a single slice.
 
       \param sliceDiff is a 2D image with the difference image of the slice determined by sliceDimension and sliceIndex.
              The difference is (pixel value in the new slice minus pixel value in the old slice).
 
       \param sliceDimension Number of the dimension which is constant for all pixels of the meant slice.
 
       \param sliceIndex Which slice to take, in the direction specified by sliceDimension. Count starts from 0.
 
       \param timeStep Which time step is changed
     */
     void SetChangedSlice(const Image *sliceDiff,
                          unsigned int sliceDimension,
                          unsigned int sliceIndex,
                          unsigned int timeStep);
     void SetChangedVolume(const Image *sliceDiff, unsigned int timeStep);
 
     /**
       \brief Generates an interpolated image for the given slice.
 
       \param sliceDimension Number of the dimension which is constant for all pixels of the meant slice.
 
       \param sliceIndex Which slice to take, in the direction specified by sliceDimension. Count starts from 0.
 
       \param currentPlane
 
       \param timeStep Which time step to use
 
       \param algorithm Optional algorithm instance to potentially benefit from caching for repeated interpolation
     */
     Image::Pointer Interpolate(unsigned int sliceDimension,
                                unsigned int sliceIndex,
                                const mitk::PlaneGeometry *currentPlane,
                                unsigned int timeStep,
                                itk::SmartPointer<ShapeBasedInterpolationAlgorithm> algorithm = nullptr);
 
     void OnImageModified(const itk::EventObject &);
 
     /**
      * Activate/Deactivate the 2D interpolation.
     */
     void Activate2DInterpolation(bool);
 
     /**
      * Enable slice extraction cache for upper and lower slices.
     */
     void EnableSliceImageCache();
 
     /**
      * Disable slice extraction cache for upper and lower slices.
     */
     void DisableSliceImageCache();
 
     /**
       \brief Get existing instance or create a new one
     */
     static SegmentationInterpolationController *GetInstance();
 
   protected:
     /**
       \brief Protected class of mitk::SegmentationInterpolationController. Don't use (you shouldn't be able to do so)!
     */
     class MITKSEGMENTATION_EXPORT SetChangedSliceOptions
     {
     public:
       SetChangedSliceOptions(
         unsigned int sd, unsigned int si, unsigned int d0, unsigned int d1, unsigned int t, const void *pixels)
         : sliceDimension(sd), sliceIndex(si), dim0(d0), dim1(d1), timeStep(t), pixelData(pixels)
       {
       }
 
       unsigned int sliceDimension;
       unsigned int sliceIndex;
       unsigned int dim0;
       unsigned int dim1;
       unsigned int timeStep;
       const void *pixelData;
     };
 
     typedef std::vector<unsigned int> DirtyVectorType;
     // typedef std::vector< DirtyVectorType[3] > TimeResolvedDirtyVectorType; // cannot work with C++, so next line is
     // used for implementation
     typedef std::vector<std::vector<DirtyVectorType>> TimeResolvedDirtyVectorType;
     typedef std::map<const Image *, SegmentationInterpolationController *> InterpolatorMapType;
 
     SegmentationInterpolationController(); // purposely hidden
     ~SegmentationInterpolationController() override;
 
     /// internal scan of a single slice
     template <typename DATATYPE>
     void ScanChangedSlice(const itk::Image<DATATYPE, 2> *, const SetChangedSliceOptions &options);
 
     template <typename TPixel, unsigned int VImageDimension>
     void ScanChangedVolume(const itk::Image<TPixel, VImageDimension> *, unsigned int timeStep);
 
     template <typename DATATYPE>
     void ScanWholeVolume(const itk::Image<DATATYPE, 3> *, const Image *volume, unsigned int timeStep);
 
     void PrintStatus();
 
     /**
      * Extract a slice and optionally use a caching mechanism if enabled.
     */
     mitk::Image::Pointer ExtractSlice(const PlaneGeometry* planeGeometry, unsigned int sliceIndex, unsigned int timeStep, bool cache = false);
 
     /**
       An array of flags. One for each dimension of the image. A flag is set, when a slice in a certain dimension
       has at least one pixel that is not 0 (which would mean that it has to be considered by the interpolation
       algorithm).
 
       E.g. flags for axial slices are stored in m_SegmentationCountInSlice[0][index].
 
       Enhanced with time steps it is now m_SegmentationCountInSlice[timeStep][0][index]
     */
     TimeResolvedDirtyVectorType m_SegmentationCountInSlice;
 
     static InterpolatorMapType s_InterpolatorForImage;
 
     Image::ConstPointer m_Segmentation;
     Image::ConstPointer m_ReferenceImage;
     bool m_BlockModified;
     bool m_2DInterpolationActivated;
 
     bool m_EnableSliceImageCache;
     std::map<std::pair<unsigned int, unsigned int>, Image::Pointer> m_SliceImageCache;
+    std::mutex m_SliceImageCacheMutex;
   };
 
 } // namespace
 
 #endif