diff --git a/Modules/Core/include/mitkPoint.h b/Modules/Core/include/mitkPoint.h
index 0436d5ae23..f8844cbae8 100644
--- a/Modules/Core/include/mitkPoint.h
+++ b/Modules/Core/include/mitkPoint.h
@@ -1,135 +1,153 @@
 /*============================================================================
 
 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 mitkPoint_h
 #define mitkPoint_h
 
 #include <itkPoint.h>
 
-#include "mitkArray.h"
-#include "mitkEqual.h"
-#include "mitkNumericConstants.h"
+#include <mitkArray.h>
+#include <mitkEqual.h>
+#include <mitkNumericConstants.h>
+
+#include <nlohmann/json.hpp>
 
 namespace mitk
 {
   //##Documentation
   //##@brief enumeration of the type a point can be
   enum PointSpecificationType
   {
     PTUNDEFINED = 0,
     PTSTART,
     PTCORNER,
     PTEDGE,
     PTEND
   };
 
   template <class TCoordRep, unsigned int NPointDimension = 3>
   class Point : public itk::Point<TCoordRep, NPointDimension>
   {
   public:
     /** Default constructor has nothing to do. */
     explicit Point<TCoordRep, NPointDimension>() : itk::Point<TCoordRep, NPointDimension>() {}
     /** Pass-through constructors for the Array base class. */
     template <typename TPointValueType>
     explicit Point(const Point<TPointValueType, NPointDimension> &r) : itk::Point<TCoordRep, NPointDimension>(r)
     {
     }
 
     template <typename TPointValueType>
     explicit Point(const TPointValueType r[NPointDimension]) : itk::Point<TCoordRep, NPointDimension>(r)
     {
     }
 
     template <typename TPointValueType>
     explicit Point(const TPointValueType &v) : itk::Point<TCoordRep, NPointDimension>(v)
     {
     }
 
     Point<TCoordRep, NPointDimension>(const mitk::Point<TCoordRep, NPointDimension> &r)
       : itk::Point<TCoordRep, NPointDimension>(r)
     {
     }
     Point<TCoordRep, NPointDimension>(const TCoordRep r[NPointDimension]) : itk::Point<TCoordRep, NPointDimension>(r) {}
     Point<TCoordRep, NPointDimension>(const TCoordRep &v) : itk::Point<TCoordRep, NPointDimension>(v) {}
     Point<TCoordRep, NPointDimension>(const itk::Point<TCoordRep, NPointDimension> &p)
       : itk::Point<TCoordRep, NPointDimension>(p)
     {
     }
 
     /**
      * Copies the elements from array array to this.
      * Note that this method will assign doubles to floats without complaining!
      *
      * @param array the array whose values shall be copied. Must overload [] operator.
      */
     template <typename ArrayType>
     void FillPoint(const ArrayType &array)
     {
       itk::FixedArray<TCoordRep, NPointDimension> *thisP =
         dynamic_cast<itk::FixedArray<TCoordRep, NPointDimension> *>(this);
       mitk::FillArray<ArrayType, TCoordRep, NPointDimension>(*thisP, array);
     }
 
     /**
      * Copies the values stored in this point into the array array.
      *
      * @param array the array which should store the values of this.
      */
     template <typename ArrayType>
     void ToArray(ArrayType array) const
     {
       mitk::ToArray<ArrayType, TCoordRep, NPointDimension>(array, *this);
     }
   };
 
+  template <class TCoordRep, unsigned int NPointDimension>
+  void to_json(nlohmann::json& j, const Point<TCoordRep, NPointDimension>& p)
+  {
+    j = nlohmann::json::array();
+
+    for (size_t i = 0; i < NPointDimension; ++i)
+      j.push_back(p[i]);
+  }
+
+  template <class TCoordRep, unsigned int NPointDimension>
+  void from_json(const nlohmann::json& j, Point<TCoordRep, NPointDimension>& p)
+  {
+    for (size_t i = 0; i < NPointDimension; ++i)
+      p[i] = j.at(i).get<TCoordRep>();
+  }
+
   typedef Point<ScalarType, 2> Point2D;
   typedef Point<ScalarType, 3> Point3D;
   typedef Point<ScalarType, 4> Point4D;
 
   typedef Point<int, 2> Point2I;
   typedef Point<int, 3> Point3I;
   typedef Point<int, 4> Point4I;
 
   /**
    * @ingroup MITKTestingAPI
    *
    * @param point1 Point to compare.
    * @param point2 Point to compare.
    * @param eps Tolerance for floating point comparison.
    * @param verbose Flag indicating detailed console output.
    * @return True if points are equal.
    */
   template <typename TCoordRep, unsigned int NPointDimension>
   inline bool Equal(const itk::Point<TCoordRep, NPointDimension> &point1,
                     const itk::Point<TCoordRep, NPointDimension> &point2,
                     TCoordRep eps = mitk::eps,
                     bool verbose = false)
   {
     bool isEqual = true;
     typename itk::Point<TCoordRep, NPointDimension>::VectorType diff = point1 - point2;
     for (unsigned int i = 0; i < NPointDimension; i++)
     {
       if (DifferenceBiggerOrEqualEps(diff[i], eps))
       {
         isEqual = false;
         break;
       }
     }
 
     ConditionalOutputOfDifference(point1, point2, eps, verbose, isEqual);
 
     return isEqual;
   }
 
 } // namespace mitk
 
 #endif
diff --git a/Modules/Core/include/mitkVector.h b/Modules/Core/include/mitkVector.h
index fca4c9047d..ac111e18ee 100644
--- a/Modules/Core/include/mitkVector.h
+++ b/Modules/Core/include/mitkVector.h
@@ -1,239 +1,257 @@
 /*============================================================================
 
 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 mitkVector_h
 #define mitkVector_h
 
 #include <itkVector.h>
 #include <vnl/vnl_vector.h>
 #include <vnl/vnl_vector_fixed.h>
 
-#include "mitkArray.h"
-#include "mitkEqual.h"
-#include "mitkExceptionMacro.h"
-#include "mitkNumericConstants.h"
+#include <mitkArray.h>
+#include <mitkEqual.h>
+#include <mitkExceptionMacro.h>
+#include <mitkNumericConstants.h>
+
+#include <nlohmann/json.hpp>
 
 namespace mitk
 {
   template <class TCoordRep, unsigned int NVectorDimension = 3>
   class Vector : public itk::Vector<TCoordRep, NVectorDimension>
   {
   public:
     /**
      * @brief Default constructor has nothing to do.
      */
     explicit Vector<TCoordRep, NVectorDimension>() : itk::Vector<TCoordRep, NVectorDimension>() {}
     /**
      * @brief Copy constructor.
      */
     explicit Vector<TCoordRep, NVectorDimension>(const mitk::Vector<TCoordRep, NVectorDimension> &r)
       : itk::Vector<TCoordRep, NVectorDimension>(r)
     {
     }
 
     /** Pass-through assignment operator for the Vector base class. */
     Vector<TCoordRep, NVectorDimension> & operator=(const Vector<TCoordRep, NVectorDimension> & r)
     {
       itk::Vector<TCoordRep, NVectorDimension>::operator=(r);
       return *this;
     }
 
     /**
      * @brief Constructor to convert from itk::Vector to mitk::Vector.
      */
     Vector<TCoordRep, NVectorDimension>(const itk::Vector<TCoordRep, NVectorDimension> &r)
       : itk::Vector<TCoordRep, NVectorDimension>(r)
     {
     }
 
     /**
      * @brief Constructor to convert an array to mitk::Vector
      * @param r the array.
      * @attention must have NVectorDimension valid arguments!
      */
     Vector<TCoordRep, NVectorDimension>(const TCoordRep r[NVectorDimension])
       : itk::Vector<TCoordRep, NVectorDimension>(r)
     {
     }
 
     /**
      * Constructor to initialize entire vector to one value.
      */
     Vector<TCoordRep, NVectorDimension>(const TCoordRep &v) : itk::Vector<TCoordRep, NVectorDimension>(v) {}
     /**
      * @brief Constructor for vnl_vectors.
      * @throws mitk::Exception if vnl_vector.size() != NVectorDimension.
      */
     Vector<TCoordRep, NVectorDimension>(const vnl_vector<TCoordRep> &vnlVector)
       : itk::Vector<TCoordRep, NVectorDimension>()
     {
       if (vnlVector.size() != NVectorDimension)
         mitkThrow() << "when constructing mitk::Vector from vnl_vector: sizes didn't match: mitk::Vector "
                     << NVectorDimension << "; vnl_vector " << vnlVector.size();
 
       for (unsigned int var = 0; (var < NVectorDimension) && (var < vnlVector.size()); ++var)
       {
         this->SetElement(var, vnlVector.get(var));
       }
     }
 
     /**
      * @brief Constructor for vnl_vector_fixed.
      */
     Vector<TCoordRep, NVectorDimension>(const vnl_vector_fixed<TCoordRep, NVectorDimension> &vnlVectorFixed)
       : itk::Vector<TCoordRep, NVectorDimension>()
     {
       for (unsigned int var = 0; var < NVectorDimension; ++var)
       {
         this->SetElement(var, vnlVectorFixed[var]);
       }
     };
 
     /**
      * Copies the elements from array array to this.
      * Note that this method will assign doubles to floats without complaining!
      *
      * @param array the array whose values shall be copied. Must overload [] operator.
      */
     template <typename ArrayType>
     void FillVector(const ArrayType &array)
     {
       itk::FixedArray<TCoordRep, NVectorDimension> *thisP =
         dynamic_cast<itk::FixedArray<TCoordRep, NVectorDimension> *>(this);
       mitk::FillArray<ArrayType, TCoordRep, NVectorDimension>(*thisP, array);
     }
 
     /**
      * Copies the values stored in this vector into the array array.d
      *
      * @param array the array which should store the values of this.
      */
     template <typename ArrayType>
     void ToArray(ArrayType array) const
     {
       mitk::ToArray<ArrayType, TCoordRep, NVectorDimension>(array, *this);
     }
 
     /**
      * @brief User defined conversion of mitk::Vector to vnl_vector.
      * Note: the conversion to mitk::Vector to vnl_vector_fixed has not been implemented since this
      * would collide with the conversion vnl_vector to vnl_vector_fixed provided by vnl.
      */
     operator vnl_vector<TCoordRep>() const { return this->GetVnlVector(); }
   }; // end mitk::Vector
 
+  template <class TCoordRep, unsigned int NVectorDimension>
+  void to_json(nlohmann::json &j, const Vector<TCoordRep, NVectorDimension> &v)
+  {
+    j = nlohmann::json::array();
+
+    for (size_t i = 0; i < NVectorDimension; ++i)
+      j.push_back(v[i]);
+  }
+
+  template <class TCoordRep, unsigned int NVectorDimension>
+  void from_json(const nlohmann::json &j, Vector<TCoordRep, NVectorDimension> &v)
+  {
+    for (size_t i = 0; i < NVectorDimension; ++i)
+      v[i] = j.at(i).get<TCoordRep>();
+  }
+
   // convenience typedefs for often used mitk::Vector representations.
 
   typedef Vector<ScalarType, 2> Vector2D;
   typedef Vector<ScalarType, 3> Vector3D;
   typedef Vector<ScalarType, 4> Vector4D;
 
   // other vector types used in MITK
   typedef vnl_vector<ScalarType> VnlVector;
 
   // The equal methods to compare vectors for equality are below:
 
   /**
    * @ingroup MITKTestingAPI
    *
    * @param vector1 Vector to compare.
    * @param vector2 Vector to compare.
    * @param eps Tolerance for floating point comparison.
    * @param verbose Flag indicating detailed console output.
    * @return True if vectors are equal.
    */
   template <typename TCoordRep, unsigned int NPointDimension>
   inline bool Equal(const itk::Vector<TCoordRep, NPointDimension> &vector1,
                     const itk::Vector<TCoordRep, NPointDimension> &vector2,
                     TCoordRep eps = mitk::eps,
                     bool verbose = false)
   {
     bool isEqual = true;
     typename itk::Vector<TCoordRep, NPointDimension>::VectorType diff = vector1 - vector2;
     for (unsigned int i = 0; i < NPointDimension; i++)
     {
       if (DifferenceBiggerOrEqualEps(diff[i], eps))
       {
         isEqual = false;
         break;
       }
     }
 
     ConditionalOutputOfDifference(vector1, vector2, eps, verbose, isEqual);
 
     return isEqual;
   }
 
   /**
    * @ingroup MITKTestingAPI
    *
    * @param vector1 Vector to compare.
    * @param vector2 Vector to compare.
    * @param eps Tolerance for floating point comparison.
    * @param verbose Flag indicating detailed console output.
    * @return True if vectors are equal.
    */
   inline bool Equal(const mitk::VnlVector &vector1,
                     const mitk::VnlVector &vector2,
                     ScalarType eps = mitk::eps,
                     bool verbose = false)
   {
     bool isEqual = true;
     mitk::VnlVector diff = vector1 - vector2;
     for (unsigned int i = 0; i < diff.size(); i++)
     {
       if (DifferenceBiggerOrEqualEps(diff[i], eps))
       {
         isEqual = false;
         break;
       }
     }
 
     ConditionalOutputOfDifference(vector1, vector2, eps, verbose, isEqual);
 
     return isEqual;
   }
 
   /**
    * @ingroup MITKTestingAPI
    *
    * @param vector1 Vector to compare.
    * @param vector2 Vector to compare.
    * @param eps Tolerance for floating point comparison.
    * @param verbose Flag indicating detailed console output.
    * @return True if vectors are equal.
    */
   template <typename TCoordRep, unsigned int NPointDimension>
   inline bool Equal(const vnl_vector_fixed<TCoordRep, NPointDimension> &vector1,
                     const vnl_vector_fixed<TCoordRep, NPointDimension> &vector2,
                     TCoordRep eps = mitk::eps,
                     bool verbose = false)
   {
     vnl_vector_fixed<TCoordRep, NPointDimension> diff = vector1 - vector2;
     bool isEqual = true;
     for (unsigned int i = 0; i < diff.size(); i++)
     {
       if (DifferenceBiggerOrEqualEps(diff[i], eps))
       {
         isEqual = false;
         break;
       }
     }
 
     ConditionalOutputOfDifference(vector1, vector2, eps, verbose, isEqual);
 
     return isEqual;
   }
 
 } // end namespace mitk
 
 #endif
diff --git a/Modules/ROI/autoload/IO/src/mitkROIIO.cpp b/Modules/ROI/autoload/IO/src/mitkROIIO.cpp
index 0354b844dc..6bdce335bb 100644
--- a/Modules/ROI/autoload/IO/src/mitkROIIO.cpp
+++ b/Modules/ROI/autoload/IO/src/mitkROIIO.cpp
@@ -1,36 +1,118 @@
 /*============================================================================
 
 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 "mitkROIIO.h"
 #include <mitkROI.h>
 #include <mitkROIIOMimeTypes.h>
 
+#include <nlohmann/json.hpp>
+
+#include <filesystem>
+#include <fstream>
+
 mitk::ROIIO::ROIIO()
   : AbstractFileIO(ROI::GetStaticNameOfClass(), MitkROIIOMimeTypes::ROI_MIMETYPE(), "MITK ROI")
 {
   this->RegisterService();
 }
 
 std::vector<mitk::BaseData::Pointer> mitk::ROIIO::DoRead()
 {
-  std::vector<BaseData::Pointer> result;
-  return result;
+  auto *stream = this->GetInputStream();
+  std::ifstream fileStream;
+
+  if (nullptr == stream)
+  {
+    auto filename = this->GetInputLocation();
+
+    if (filename.empty() || !std::filesystem::exists(filename))
+      mitkThrow() << "Invalid or nonexistent filename: \"" << filename << "\"!";
+
+    fileStream.open(filename);
+
+    if (!fileStream.is_open())
+      mitkThrow() << "Could not open file \"" << filename << "\" for reading!";
+
+    stream = &fileStream;
+  }
+
+  nlohmann::json json;
+
+  try
+  {
+    json = nlohmann::json::parse(*stream);
+  }
+  catch (const nlohmann::json::exception &e)
+  {
+    mitkThrow() << e.what();
+  }
+
+  if (!json.is_object())
+    mitkThrow() << "Unknown file format (expected JSON object as root)!";
+
+  if ("MITK ROI" != json.value("FileFormat", ""))
+    mitkThrow() << "Unknown file format (expected \"MITK ROI\")!";
+
+  if (1 != json.value<int>("Version", 0))
+    mitkThrow() << "Unknown file format version (expected \"1\")!";
+
+  auto geometry = Geometry3D::New();
+
+  if (json.contains("Geometry"))
+  {
+    auto jsonGeometry = json["Geometry"];
+
+    if (!jsonGeometry.is_object())
+      mitkThrow() << "Geometry is expected to be a JSON object.";
+
+    auto geometryType = jsonGeometry.value<std::string>("Type", "Embedded");
+
+    if (geometryType != "Embedded")
+      mitkThrow() << "Unknown geometry type \"" << geometryType << "\"!";
+
+    if (jsonGeometry.contains("Origin"))
+      geometry->SetOrigin(jsonGeometry["Origin"].get<Point3D>());
+
+    if (jsonGeometry.contains("Spacing"))
+      geometry->SetSpacing(jsonGeometry["Spacing"].get<Vector3D>());
+  }
+
+  if (!json.contains("ROIs") || !json["ROIs"].is_array())
+    mitkThrow() << "ROIs array not found!";
+
+  std::vector<BaseData::Pointer> results;
+
+  try
+  {
+    for (const auto& roi : json["ROIs"])
+    {
+      auto result = ROI::New();
+      result->SetGeometry(geometry);
+      results.push_back(result.GetPointer());
+    }
+  }
+  catch (const nlohmann::json::type_error &e)
+  {
+    mitkThrow() << e.what();
+  }
+
+  return results;
 }
 
 void mitk::ROIIO::Write()
 {
 }
 
 mitk::ROIIO* mitk::ROIIO::IOClone() const
 {
   return new ROIIO(*this);
 }