- remove list of views from base

- fix frame_decorator in views
- use transforms and frame_decorators as cache keys
This commit is contained in:
Wim Pomp
2023-08-19 12:08:04 +02:00
parent 3dbed27078
commit cf7f2b6e1e
6 changed files with 18 additions and 47 deletions

1
.gitignore vendored
View File

@@ -8,3 +8,4 @@
/ndbioimage/_version.py /ndbioimage/_version.py
/ndbioimage/jars /ndbioimage/jars
/tests/files/* /tests/files/*
/poetry.lock

View File

@@ -367,13 +367,12 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin):
raise ReaderNotFoundError(f'No reader found for {path}.') raise ReaderNotFoundError(f'No reader found for {path}.')
def __init__(self, base=None, slice=None, shape=(0, 0, 0, 0, 0), dtype=None, def __init__(self, base=None, slice=None, shape=(0, 0, 0, 0, 0), dtype=None,
transform=False, drift=False, beadfile=None): transform=False, drift=False, beadfile=None, frame_decorator=None):
self.base = base self.base = base
self.slice = slice self.slice = slice
self._shape = Shape(shape) self._shape = Shape(shape)
self.dtype = dtype self.dtype = dtype
self.views = [] self.frame_decorator = frame_decorator
self._frame_decorator = None
self.transform = transform self.transform = transform
self.drift = drift self.drift = drift
@@ -397,7 +396,7 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin):
if k not in a: if k not in a:
yield k yield k
for idx in unique_yield(list(self.cache.keys()), for idx in unique_yield([key[:3] for key in self.cache.keys()],
product(range(self.shape['c']), range(self.shape['z']), range(self.shape['t']))): product(range(self.shape['c']), range(self.shape['z']), range(self.shape['t']))):
xyczt = (slice(None), slice(None)) + idx xyczt = (slice(None), slice(None)) + idx
in_idx = tuple(xyczt['xyczt'.find(i)] for i in self.axes) in_idx = tuple(xyczt['xyczt'.find(i)] for i in self.axes)
@@ -409,18 +408,10 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin):
return self return self
def __exit__(self, *args, **kwargs): def __exit__(self, *args, **kwargs):
exception = None if not self.isclosed:
for view in self.views:
try:
view.__exit__()
except Exception as e:
exception = e
self.views = []
if hasattr(self, 'close') and not self.isclosed:
self.close()
self.isclosed = True self.isclosed = True
if exception: if hasattr(self, 'close'):
raise exception self.close()
def __getitem__(self, n): def __getitem__(self, n):
""" slice like a numpy array but return an Imread instance """ """ slice like a numpy array but return an Imread instance """
@@ -483,22 +474,11 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin):
self.__dict__.update(state) self.__dict__.update(state)
if isinstance(self, AbstractReader): if isinstance(self, AbstractReader):
self.open() self.open()
self.views = []
self.cache = DequeDict(16) self.cache = DequeDict(16)
def __str__(self): def __str__(self):
return str(self.path) return str(self.path)
# TODO: this is causing problems when multiprocessing and doesn't work anyway
# def __del__(self):
# if not self.copies:
# if self.base is None:
# self.__exit__()
# else:
# self.base.views.remove(self)
def __array__(self, dtype=None): def __array__(self, dtype=None):
block = self.block(*self.slice) block = self.block(*self.slice)
axes_idx = [self.shape.axes.find(i) for i in 'xyczt'] axes_idx = [self.shape.axes.find(i) for i in 'xyczt']
@@ -691,15 +671,6 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin):
return return
return return
@property
def frame_decorator(self):
return self._frame_decorator
@frame_decorator.setter
def frame_decorator(self, decorator):
self._frame_decorator = decorator
self.cache = DequeDict(self.cache.maxlen)
@property @property
def ndim(self): def ndim(self):
return len(self.shape) return len(self.shape)
@@ -940,6 +911,7 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin):
@wraps(np.sum) @wraps(np.sum)
def sum(self, axis=None, dtype=None, out=None, keepdims=False, initial=None, where=True, **kwargs): def sum(self, axis=None, dtype=None, out=None, keepdims=False, initial=None, where=True, **kwargs):
return self.__array_fun__([np.sum], axis, dtype, out, keepdims, [initial], where) return self.__array_fun__([np.sum], axis, dtype, out, keepdims, [initial], where)
@wraps(np.swapaxes) @wraps(np.swapaxes)
def swapaxes(self, axis1, axis2): def swapaxes(self, axis1, axis2):
new = self.copy() new = self.copy()
@@ -992,7 +964,7 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin):
""" returns 5D block of frames """ """ returns 5D block of frames """
x, y, c, z, t = [np.arange(self.shape[i]) if e is None else np.array(e, ndmin=1) x, y, c, z, t = [np.arange(self.shape[i]) if e is None else np.array(e, ndmin=1)
for i, e in zip('xyczt', (x, y, c, z, t))] for i, e in zip('xyczt', (x, y, c, z, t))]
d = np.full((len(x), len(y), len(c), len(z), len(t)), np.nan, self.dtype) d = np.empty((len(x), len(y), len(c), len(z), len(t)), self.dtype)
for (ci, cj), (zi, zj), (ti, tj) in product(enumerate(c), enumerate(z), enumerate(t)): for (ci, cj), (zi, zj), (ti, tj) in product(enumerate(c), enumerate(z), enumerate(t)):
d[:, :, ci, zi, ti] = self.frame(cj, zj, tj)[x][:, y] d[:, :, ci, zi, ti] = self.frame(cj, zj, tj)[x][:, y]
return d return d
@@ -1013,7 +985,7 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin):
t %= self.base.shape['t'] t %= self.base.shape['t']
# cache last n (default 16) frames in memory for speed (~250x faster) # cache last n (default 16) frames in memory for speed (~250x faster)
key = (c, z, t, self.transform is None, self.frame_decorator is None) key = (c, z, t, self.transform, self.frame_decorator)
if key in self.cache: if key in self.cache:
self.cache.move_to_end(key) self.cache.move_to_end(key)
f = self.cache[key] f = self.cache[key]
@@ -1170,8 +1142,7 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin):
class View(Imread): class View(Imread):
def __init__(self, base, dtype=None, transform=None, drift=None, beadfile=None): def __init__(self, base, dtype=None, transform=None, drift=None, beadfile=None):
super().__init__(base.base, base.slice, base.shape, dtype or base.dtype, transform or base.transform, super().__init__(base.base, base.slice, base.shape, dtype or base.dtype, transform or base.transform,
drift or base.drift, beadfile or base.beadfile) drift or base.drift, beadfile or base.beadfile, base.frame_decorator)
base.views.append(self)
self.set_transform() self.set_transform()
def __getattr__(self, item): def __getattr__(self, item):
@@ -1180,7 +1151,6 @@ class View(Imread):
return self.base.__getattribute__(item) return self.base.__getattribute__(item)
class AbstractReader(Imread, metaclass=ABCMeta): class AbstractReader(Imread, metaclass=ABCMeta):
""" class to read image files, while taking good care of important metadata, """ class to read image files, while taking good care of important metadata,
currently optimized for .czi files, but can open anything that bioformats can handle currently optimized for .czi files, but can open anything that bioformats can handle

View File

@@ -52,8 +52,8 @@ class Reader(AbstractReader, ABC):
model.Image( model.Image(
pixels=model.Pixels( pixels=model.Pixels(
size_c=size_c, size_z=size_z, size_t=size_t, size_x=size_x, size_y=size_y, size_c=size_c, size_z=size_z, size_t=size_t, size_x=size_x, size_y=size_y,
dimension_order="XYCZT", type=pixel_type, dimension_order="XYCZT", type=pixel_type),
objective_settings=model.ObjectiveSettings(id="Objective:0")))) objective_settings=model.ObjectiveSettings(id="Objective:0")))
for c, z, t in product(range(size_c), range(size_z), range(size_t)): for c, z, t in product(range(size_c), range(size_z), range(size_t)):
ome.images[0].pixels.planes.append(model.Plane(the_c=c, the_z=z, the_t=t, delta_t=0)) ome.images[0].pixels.planes.append(model.Plane(the_c=c, the_z=z, the_t=t, delta_t=0))
return ome return ome

View File

@@ -32,8 +32,8 @@ class Reader(AbstractReader, ABC):
model.Image( model.Image(
pixels=model.Pixels( pixels=model.Pixels(
size_c=size_c, size_z=size_z, size_t=size_t, size_x=size_x, size_y=size_y, size_c=size_c, size_z=size_z, size_t=size_t, size_x=size_x, size_y=size_y,
dimension_order="XYCZT", type=pixel_type, dimension_order="XYCZT", type=pixel_type),
objective_settings=model.ObjectiveSettings(id="Objective:0")))) objective_settings=model.ObjectiveSettings(id="Objective:0")))
for c, z, t in product(range(size_c), range(size_z), range(size_t)): for c, z, t in product(range(size_c), range(size_z), range(size_t)):
ome.images[0].pixels.planes.append(model.Plane(the_c=c, the_z=z, the_t=t, delta_t=0)) ome.images[0].pixels.planes.append(model.Plane(the_c=c, the_z=z, the_t=t, delta_t=0))
return ome return ome

View File

@@ -107,7 +107,7 @@ class Reader(AbstractReader, ABC):
return ome return ome
def open(self): def open(self):
if re.match(r'(?:\d+\-)?Pos.*', self.path.name) is None: if re.match(r'(?:\d+-)?Pos.*', self.path.name) is None:
path = self.path / f"Pos{self.series}" path = self.path / f"Pos{self.series}"
else: else:
path = self.path path = self.path

View File

@@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "ndbioimage" name = "ndbioimage"
version = "2023.8.0" version = "2023.8.1"
description = "Bio image reading, metadata and some affine registration." description = "Bio image reading, metadata and some affine registration."
authors = ["W. Pomp <w.pomp@nki.nl>"] authors = ["W. Pomp <w.pomp@nki.nl>"]
license = "GPLv3" license = "GPLv3"