- remove list of views from base
- fix frame_decorator in views - use transforms and frame_decorators as cache keys
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -8,3 +8,4 @@
|
|||||||
/ndbioimage/_version.py
|
/ndbioimage/_version.py
|
||||||
/ndbioimage/jars
|
/ndbioimage/jars
|
||||||
/tests/files/*
|
/tests/files/*
|
||||||
|
/poetry.lock
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
Reference in New Issue
Block a user