diff --git a/model_server/base/accessors.py b/model_server/base/accessors.py
index 712bbacf19296201775e1d7d49ef45b356ac1d1d..c6a787bc4c12918b64d06e95c97c50cf4ad2fc53 100644
--- a/model_server/base/accessors.py
+++ b/model_server/base/accessors.py
@@ -8,6 +8,7 @@ from skimage.io import imread
 import czifile
 import tifffile
 
+from extensions.chaeo.accessors import InvalidDataForPatchStackError
 from model_server.base.process import is_mask
 
 class GenericImageDataAccessor(ABC):
@@ -234,4 +235,68 @@ class InvalidAxisKey(Error):
     pass
 
 class InvalidDataShape(Error):
-    pass
\ No newline at end of file
+    pass
+
+
+class PatchStack(InMemoryDataAccessor):
+
+    def __init__(self, data):
+        """
+        A sequence of n (generally) color 3D images of the same size
+        :param data: either a list of np.ndarrays of size YXCZ, or np.ndarray of size PYXCZ
+        """
+
+        if isinstance(data, list):  # list of YXCZ patches
+            n = len(data)
+            yxcz_shape = np.array([e.shape for e in data]).max(axis=0)
+            nda = np.zeros(
+                (n, *yxcz_shape), dtype=data[0].dtype
+            )
+            for i in range(0, len(data)):
+                s = tuple([slice(0, c) for c in data[i].shape])
+                nda[i][s] = data[i]
+
+        elif isinstance(data, np.ndarray) and len(data.shape) == 5:  # interpret as PYXCZ
+            nda = data
+        else:
+            raise InvalidDataForPatchStackError(f'Cannot create accessor from {type(data)}')
+
+        assert nda.ndim == 5
+        self._data = nda
+
+    def iat(self, i):
+        return self.data[i, :, :, :, :]
+
+    def iat_yxcz(self, i):
+        return self.iat(i)
+
+    @property
+    def count(self):
+        return self.shape_dict['P']
+
+    @property
+    def shape_dict(self):
+        return dict(zip(('P', 'Y', 'X', 'C', 'Z'), self.data.shape))
+
+    def get_list(self):
+        n = self.nz
+        return [self.data[:, :, 0, zi] for zi in range(0, n)]
+
+    @property
+    def pyxcz(self):
+        return self.data
+
+    @property
+    def pczyx(self):
+        return np.moveaxis(
+            self.data,
+            [0, 3, 4, 1, 2],
+            [0, 1, 2, 3, 4]
+        )
+    @property
+    def shape(self):
+        return self.data.shape
+
+    @property
+    def shape_dict(self):
+        return dict(zip(('P', 'Y', 'X', 'C', 'Z'), self.data.shape))
diff --git a/model_server/base/roiset.py b/model_server/base/roiset.py
index 608e9d0965f5ea68f6186b36eb9c591dcb91f6fa..819f8552660f1051f2bf3e713faf74d21e58d508 100644
--- a/model_server/base/roiset.py
+++ b/model_server/base/roiset.py
@@ -17,7 +17,8 @@ from model_server.base.accessors import GenericImageDataAccessor, InMemoryDataAc
 from model_server.base.models import InstanceSegmentationModel
 from model_server.base.process import pad, rescale, resample_to_8bit, make_rgb
 from base.annotators import draw_box_on_patch, draw_contours_on_patch, draw_boxes_on_3d_image
-from model_server.extensions.chaeo.accessors import write_patch_to_file, PatchStack
+from model_server.extensions.chaeo.accessors import write_patch_to_file
+from base.accessors import PatchStack
 from base.process import mask_largest_object
 
 
diff --git a/model_server/extensions/chaeo/accessors.py b/model_server/extensions/chaeo/accessors.py
index 45eee67b63847ba4df80814fd2d6a1fc0f154550..2307d80ccb0b90bd70e2ca03c6a3b14800069e65 100644
--- a/model_server/extensions/chaeo/accessors.py
+++ b/model_server/extensions/chaeo/accessors.py
@@ -7,67 +7,6 @@ from tifffile import imwrite
 from base.process import make_rgb
 from model_server.base.accessors import generate_file_accessor, InMemoryDataAccessor
 
-class MonoPatchStack(InMemoryDataAccessor):
-
-    def __init__(self, data):
-        """
-        A sequence of n monochrome images of the same size
-        :param data: either np.ndarray of dimensions YXn, or a list of np.ndarrays of size YX
-        """
-
-        if isinstance(data, np.ndarray):
-            if data.ndim == 3:  # interpret as YXZ
-                self._data = np.expand_dims(data, 2)
-            elif data.ndim == 4:  # interpret as a copy another patch stack
-                self._data = data
-            else:
-                raise InvalidDataForPatchStackError()
-        elif isinstance(data, list): # list of YX patches
-            if len(data) == 0:
-                self._data = np.ndarray([0, 0, 0, 0], dtype='uin9')
-            elif len(data) == 1:
-                self._data = np.expand_dims(
-                    np.array(
-                        data[0].squeeze()
-                    ),
-                    (2, 3)
-                )
-            else:
-                nda = np.array(data).squeeze()
-                assert nda.ndim == 3
-                self._data = np.expand_dims(
-                    np.moveaxis(
-                        nda,
-                        [1, 2, 0],
-                        [0, 1, 2]),
-                    2
-                )
-        else:
-            raise InvalidDataForPatchStackError(f'Cannot create accessor from {type(data)}')
-
-    def make_tczyx(self):
-        assert self.chroma == 1
-        tyx = np.moveaxis(
-            self.data[:, :, 0, :], # YX(C)Z
-            [2, 0, 1],
-            [0, 1, 2]
-        )
-        return np.expand_dims(tyx, (1, 2))
-
-    @property
-    def count(self):
-        return self.nz
-
-    def iat(self, i):
-        return self.data[:, :, 0, i]
-
-    def iat_yxcz(self, i):
-        return np.expand_dims(self.iat(i), (2, 3))
-
-    def get_list(self):
-        n = self.nz
-        return [self.data[:, :, 0, zi] for zi in range(0, n)]
-
 
 class MonoPatchStackFromFile(MonoPatchStack):
     def __init__(self, fpath):
@@ -81,70 +20,6 @@ class MonoPatchStackFromFile(MonoPatchStack):
         return self.file_acc.fpath
 
 
-class PatchStack(InMemoryDataAccessor):
-
-    def __init__(self, data):
-        """
-        A sequence of n (generally) color 3D images of the same size
-        :param data: either a list of np.ndarrays of size YXCZ, or np.ndarray of size PYXCZ
-        """
-
-        if isinstance(data, list):  # list of YXCZ patches
-            n = len(data)
-            yxcz_shape = np.array([e.shape for e in data]).max(axis=0)
-            nda = np.zeros(
-                (n, *yxcz_shape), dtype=data[0].dtype
-            )
-            for i in range(0, len(data)):
-                s = tuple([slice(0, c) for c in data[i].shape])
-                nda[i][s] = data[i]
-
-        elif isinstance(data, np.ndarray) and len(data.shape) == 5:  # interpret as PYXCZ
-            nda = data
-        else:
-            raise InvalidDataForPatchStackError(f'Cannot create accessor from {type(data)}')
-
-        assert nda.ndim == 5
-        self._data = nda
-
-    def iat(self, i):
-        return self.data[i, :, :, :, :]
-
-    def iat_yxcz(self, i):
-        return self.iat(i)
-
-    @property
-    def count(self):
-        return self.shape_dict['P']
-
-    @property
-    def shape_dict(self):
-        return dict(zip(('P', 'Y', 'X', 'C', 'Z'), self.data.shape))
-
-    def get_list(self):
-        n = self.nz
-        return [self.data[:, :, 0, zi] for zi in range(0, n)]
-
-    @property
-    def pyxcz(self):
-        return self.data
-
-    @property
-    def pczyx(self):
-        return np.moveaxis(
-            self.data,
-            [0, 3, 4, 1, 2],
-            [0, 1, 2, 3, 4]
-        )
-    @property
-    def shape(self):
-        return self.data.shape
-
-    @property
-    def shape_dict(self):
-        return dict(zip(('P', 'Y', 'X', 'C', 'Z'), self.data.shape))
-
-
 def write_patch_to_file(where, fname, yxcz):
     ext = fname.split('.')[-1].upper()
     where.mkdir(parents=True, exist_ok=True)
diff --git a/model_server/extensions/chaeo/tests/test_accessors.py b/model_server/extensions/chaeo/tests/test_accessors.py
index 0aa364c794de074524ecc231ee602208a8c99b4a..a92c058c6d9c490ba47f9b5d0d250c7acd8a8030 100644
--- a/model_server/extensions/chaeo/tests/test_accessors.py
+++ b/model_server/extensions/chaeo/tests/test_accessors.py
@@ -3,8 +3,8 @@ import unittest
 import numpy as np
 
 from model_server.conf.testing import monozstackmask
-from model_server.extensions.chaeo.accessors import MonoPatchStackFromFile, PatchStack
-
+from model_server.extensions.chaeo.accessors import MonoPatchStackFromFile
+from base.accessors import PatchStack
 
 
 class TestMultipositionCziImageFileAccess(unittest.TestCase):
diff --git a/model_server/extensions/ilastik/models.py b/model_server/extensions/ilastik/models.py
index 9a6de5e86bf9d13a1aa2d7e62af7ba974acd2920..91493a2bed5fc0f676206a3cf1b75a3ff4f7c00b 100644
--- a/model_server/extensions/ilastik/models.py
+++ b/model_server/extensions/ilastik/models.py
@@ -5,7 +5,7 @@ import numpy as np
 import vigra
 
 import model_server.extensions.ilastik.conf
-from extensions.chaeo.accessors import PatchStack
+from base.accessors import PatchStack
 from model_server.base.accessors import GenericImageDataAccessor, InMemoryDataAccessor
 from model_server.base.models import Model, ImageToImageModel, InstanceSegmentationModel, InvalidInputImageError, ParameterExpectedError, SemanticSegmentationModel