- bugfix: swap xy.
This commit is contained in:
+42
-42
@@ -106,7 +106,7 @@ def get_ome(path):
|
|||||||
|
|
||||||
|
|
||||||
class Shape(tuple):
|
class Shape(tuple):
|
||||||
def __new__(cls, shape, axes='xyczt'):
|
def __new__(cls, shape, axes='yxczt'):
|
||||||
if isinstance(shape, Shape):
|
if isinstance(shape, Shape):
|
||||||
axes = shape.axes
|
axes = shape.axes
|
||||||
instance = super().__new__(cls, shape)
|
instance = super().__new__(cls, shape)
|
||||||
@@ -122,8 +122,8 @@ class Shape(tuple):
|
|||||||
return super().__getitem__(n)
|
return super().__getitem__(n)
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def xyczt(self):
|
def yxczt(self):
|
||||||
return tuple(self[i] for i in 'xyczt')
|
return tuple(self[i] for i in 'yxczt')
|
||||||
|
|
||||||
|
|
||||||
class Imread(np.lib.mixins.NDArrayOperatorsMixin, ABC):
|
class Imread(np.lib.mixins.NDArrayOperatorsMixin, ABC):
|
||||||
@@ -225,8 +225,8 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin, ABC):
|
|||||||
|
|
||||||
for idx in unique_yield([key[:3] for key in 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
|
yxczt = (slice(None), slice(None)) + idx
|
||||||
in_idx = tuple(xyczt['xyczt'.find(i)] for i in self.axes)
|
in_idx = tuple(yxczt['yxczt'.find(i)] for i in self.axes)
|
||||||
if item in np.asarray(self[in_idx]):
|
if item in np.asarray(self[in_idx]):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
@@ -266,7 +266,7 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin, ABC):
|
|||||||
while len(n) < self.ndim:
|
while len(n) < self.ndim:
|
||||||
n.append(None)
|
n.append(None)
|
||||||
|
|
||||||
axes_idx = [self.shape.axes.find(i) for i in 'xyczt']
|
axes_idx = [self.shape.axes.find(i) for i in 'yxczt']
|
||||||
n = [n[j] if 0 <= j < len(n) else None for j in axes_idx] # reorder n
|
n = [n[j] if 0 <= j < len(n) else None for j in axes_idx] # reorder n
|
||||||
|
|
||||||
new_slice = []
|
new_slice = []
|
||||||
@@ -283,7 +283,7 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin, ABC):
|
|||||||
new = View(self)
|
new = View(self)
|
||||||
new.slice = new_slice
|
new.slice = new_slice
|
||||||
new._shape = Shape([1 if isinstance(s, Number) else len(s) for s in new_slice])
|
new._shape = Shape([1 if isinstance(s, Number) else len(s) for s in new_slice])
|
||||||
new.axes = ''.join(j for j in self.axes if j in [i for i, s in zip('xyczt', new_slice)
|
new.axes = ''.join(j for j in self.axes if j in [i for i, s in zip('yxczt', new_slice)
|
||||||
if not isinstance(s, Number)])
|
if not isinstance(s, Number)])
|
||||||
return new
|
return new
|
||||||
|
|
||||||
@@ -308,7 +308,7 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin, ABC):
|
|||||||
|
|
||||||
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 'yxczt']
|
||||||
axes_squeeze = tuple({i for i, j in enumerate(axes_idx) if j == -1}.union(
|
axes_squeeze = tuple({i for i, j in enumerate(axes_idx) if j == -1}.union(
|
||||||
{i for i, j in enumerate(self.slice) if isinstance(j, Number)}))
|
{i for i, j in enumerate(self.slice) if isinstance(j, Number)}))
|
||||||
block = block.squeeze(axes_squeeze)
|
block = block.squeeze(axes_squeeze)
|
||||||
@@ -316,7 +316,7 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin, ABC):
|
|||||||
block = block.astype(dtype)
|
block = block.astype(dtype)
|
||||||
if block.ndim == 0:
|
if block.ndim == 0:
|
||||||
return block.item()
|
return block.item()
|
||||||
axes = ''.join(j for i, j in enumerate('xyczt') if i not in axes_squeeze)
|
axes = ''.join(j for i, j in enumerate('yxczt') if i not in axes_squeeze)
|
||||||
return block.transpose([axes.find(i) for i in self.shape.axes if i in axes])
|
return block.transpose([axes.find(i) for i in self.shape.axes if i in axes])
|
||||||
|
|
||||||
def __array_arg_fun__(self, fun, axis=None, out=None):
|
def __array_arg_fun__(self, fun, axis=None, out=None):
|
||||||
@@ -324,8 +324,8 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin, ABC):
|
|||||||
if axis is None:
|
if axis is None:
|
||||||
value = arg = None
|
value = arg = None
|
||||||
for idx in product(range(self.shape['c']), range(self.shape['z']), range(self.shape['t'])):
|
for idx in product(range(self.shape['c']), range(self.shape['z']), range(self.shape['t'])):
|
||||||
xyczt = (slice(None), slice(None)) + idx
|
yxczt = (slice(None), slice(None)) + idx
|
||||||
in_idx = tuple(xyczt['xyczt'.find(i)] for i in self.axes)
|
in_idx = tuple(yxczt['yxczt'.find(i)] for i in self.axes)
|
||||||
new = np.asarray(self[in_idx])
|
new = np.asarray(self[in_idx])
|
||||||
new_arg = np.unravel_index(fun(new), new.shape)
|
new_arg = np.unravel_index(fun(new), new.shape)
|
||||||
new_value = new[new_arg]
|
new_value = new[new_arg]
|
||||||
@@ -336,7 +336,7 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin, ABC):
|
|||||||
i = fun((value, new_value))
|
i = fun((value, new_value))
|
||||||
arg = (arg, new_arg + idx)[i]
|
arg = (arg, new_arg + idx)[i]
|
||||||
value = (value, new_value)[i]
|
value = (value, new_value)[i]
|
||||||
axes = ''.join(i for i in self.axes if i in 'xy') + 'czt'
|
axes = ''.join(i for i in self.axes if i in 'yx') + 'czt'
|
||||||
arg = np.ravel_multi_index([arg[axes.find(i)] for i in self.axes], self.shape)
|
arg = np.ravel_multi_index([arg[axes.find(i)] for i in self.axes], self.shape)
|
||||||
if out is None:
|
if out is None:
|
||||||
return arg
|
return arg
|
||||||
@@ -356,19 +356,19 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin, ABC):
|
|||||||
out_axes.pop(axis_idx)
|
out_axes.pop(axis_idx)
|
||||||
if out is None:
|
if out is None:
|
||||||
out = np.zeros(out_shape, int)
|
out = np.zeros(out_shape, int)
|
||||||
if axis_str in 'xy':
|
if axis_str in 'yx':
|
||||||
for idx in product(range(self.shape['c']), range(self.shape['z']), range(self.shape['t'])):
|
for idx in product(range(self.shape['c']), range(self.shape['z']), range(self.shape['t'])):
|
||||||
xyczt = (slice(None), slice(None)) + idx
|
yxczt = (slice(None), slice(None)) + idx
|
||||||
out_idx = tuple(xyczt['xyczt'.find(i)] for i in out_axes)
|
out_idx = tuple(yxczt['yxczt'.find(i)] for i in out_axes)
|
||||||
in_idx = tuple(xyczt['xyczt'.find(i)] for i in self.axes)
|
in_idx = tuple(yxczt['yxczt'.find(i)] for i in self.axes)
|
||||||
new = self[in_idx]
|
new = self[in_idx]
|
||||||
out[out_idx] = fun(np.asarray(new), new.axes.find(axis_str))
|
out[out_idx] = fun(np.asarray(new), new.axes.find(axis_str))
|
||||||
else:
|
else:
|
||||||
value = np.zeros(out.shape, self.dtype)
|
value = np.zeros(out.shape, self.dtype)
|
||||||
for idx in product(range(self.shape['c']), range(self.shape['z']), range(self.shape['t'])):
|
for idx in product(range(self.shape['c']), range(self.shape['z']), range(self.shape['t'])):
|
||||||
xyczt = (slice(None), slice(None)) + idx
|
yxczt = (slice(None), slice(None)) + idx
|
||||||
out_idx = tuple(xyczt['xyczt'.find(i)] for i in out_axes)
|
out_idx = tuple(yxczt['yxczt'.find(i)] for i in out_axes)
|
||||||
in_idx = tuple(xyczt['xyczt'.find(i)] for i in self.axes)
|
in_idx = tuple(yxczt['yxczt'.find(i)] for i in self.axes)
|
||||||
new_value = self[in_idx]
|
new_value = self[in_idx]
|
||||||
new_arg = np.full_like(new_value, idx['czt'.find(axis_str)])
|
new_arg = np.full_like(new_value, idx['czt'.find(axis_str)])
|
||||||
if idx['czt'.find(axis_str)] == 0:
|
if idx['czt'.find(axis_str)] == 0:
|
||||||
@@ -401,8 +401,8 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin, ABC):
|
|||||||
# TODO: smarter transforms
|
# TODO: smarter transforms
|
||||||
if axis is None:
|
if axis is None:
|
||||||
for idx in product(range(self.shape['c']), range(self.shape['z']), range(self.shape['t'])):
|
for idx in product(range(self.shape['c']), range(self.shape['z']), range(self.shape['t'])):
|
||||||
xyczt = (slice(None), slice(None)) + idx
|
yxczt = (slice(None), slice(None)) + idx
|
||||||
in_idx = tuple(xyczt['xyczt'.find(i)] for i in self.axes)
|
in_idx = tuple(yxczt['yxczt'.find(i)] for i in self.axes)
|
||||||
w = where if where is None or isinstance(where, bool) else where[in_idx]
|
w = where if where is None or isinstance(where, bool) else where[in_idx]
|
||||||
initials = [fun(np.asarray(ffun(self[in_idx])), initial=initial, where=w)
|
initials = [fun(np.asarray(ffun(self[in_idx])), initial=initial, where=w)
|
||||||
for fun, ffun, initial in zip(funs, ffuns, initials)]
|
for fun, ffun, initial in zip(funs, ffuns, initials)]
|
||||||
@@ -430,13 +430,13 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin, ABC):
|
|||||||
out_axes.pop(axis_idx)
|
out_axes.pop(axis_idx)
|
||||||
if out is None:
|
if out is None:
|
||||||
out = np.zeros(out_shape, dtype)
|
out = np.zeros(out_shape, dtype)
|
||||||
if axis_str in 'xy':
|
if axis_str in 'yx':
|
||||||
xy = 'xy' if self.axes.find('x') < self.axes.find('y') else 'yx'
|
yx = 'yx' if self.axes.find('x') > self.axes.find('y') else 'yx'
|
||||||
frame_ax = xy.find(axis_str)
|
frame_ax = yx.find(axis_str)
|
||||||
for idx in product(range(self.shape['c']), range(self.shape['z']), range(self.shape['t'])):
|
for idx in product(range(self.shape['c']), range(self.shape['z']), range(self.shape['t'])):
|
||||||
xyczt = (slice(None), slice(None)) + idx
|
yxczt = (slice(None), slice(None)) + idx
|
||||||
out_idx = tuple(xyczt['xyczt'.find(i)] for i in out_axes)
|
out_idx = tuple(yxczt['yxczt'.find(i)] for i in out_axes)
|
||||||
in_idx = tuple(xyczt['xyczt'.find(i)] for i in self.axes)
|
in_idx = tuple(yxczt['yxczt'.find(i)] for i in self.axes)
|
||||||
w = where if where is None or isinstance(where, bool) else where[in_idx]
|
w = where if where is None or isinstance(where, bool) else where[in_idx]
|
||||||
res = cfun(*[fun(ffun(self[in_idx]), frame_ax, initial=initial, where=w)
|
res = cfun(*[fun(ffun(self[in_idx]), frame_ax, initial=initial, where=w)
|
||||||
for fun, ffun, initial in zip(funs, ffuns, initials)])
|
for fun, ffun, initial in zip(funs, ffuns, initials)])
|
||||||
@@ -444,9 +444,9 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin, ABC):
|
|||||||
else:
|
else:
|
||||||
tmps = [np.zeros(out_shape) for _ in ffuns]
|
tmps = [np.zeros(out_shape) for _ in ffuns]
|
||||||
for idx in product(range(self.shape['c']), range(self.shape['z']), range(self.shape['t'])):
|
for idx in product(range(self.shape['c']), range(self.shape['z']), range(self.shape['t'])):
|
||||||
xyczt = (slice(None), slice(None)) + idx
|
yxczt = (slice(None), slice(None)) + idx
|
||||||
out_idx = tuple(xyczt['xyczt'.find(i)] for i in out_axes)
|
out_idx = tuple(yxczt['yxczt'.find(i)] for i in out_axes)
|
||||||
in_idx = tuple(xyczt['xyczt'.find(i)] for i in self.axes)
|
in_idx = tuple(yxczt['yxczt'.find(i)] for i in self.axes)
|
||||||
|
|
||||||
if idx['czt'.find(axis_str)] == 0:
|
if idx['czt'.find(axis_str)] == 0:
|
||||||
w = where if where is None or isinstance(where, bool) else (where[in_idx],)
|
w = where if where is None or isinstance(where, bool) else (where[in_idx],)
|
||||||
@@ -512,7 +512,7 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin, ABC):
|
|||||||
if isinstance(value, Shape):
|
if isinstance(value, Shape):
|
||||||
self._shape = value
|
self._shape = value
|
||||||
else:
|
else:
|
||||||
self._shape = Shape((value['xyczt'.find(i.lower())] for i in self.axes), self.axes)
|
self._shape = Shape((value['yxczt'.find(i.lower())] for i in self.axes), self.axes)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def summary(self):
|
def summary(self):
|
||||||
@@ -730,13 +730,13 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin, ABC):
|
|||||||
new.dtype = dtype
|
new.dtype = dtype
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def block(self, x=None, y=None, c=None, z=None, t=None):
|
def block(self, y=None, x=None, c=None, z=None, t=None):
|
||||||
""" 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)
|
y, x, 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('yxczt', (y, x, c, z, t)))
|
||||||
d = np.empty((len(x), len(y), len(c), len(z), len(t)), self.dtype)
|
d = np.empty((len(y), len(x), 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)[y][:, x]
|
||||||
return d
|
return d
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
@@ -906,7 +906,7 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin, ABC):
|
|||||||
view.transform = Transforms.from_file(file, C=False)
|
view.transform = Transforms.from_file(file, C=False)
|
||||||
except Exception: # noqa
|
except Exception: # noqa
|
||||||
view.transform = Transforms().with_drift(self)
|
view.transform = Transforms().with_drift(self)
|
||||||
view.transform.adapt(view.frameoffset, view.shape.xyczt, view.channel_names)
|
view.transform.adapt(view.frameoffset, view.shape.yxczt, view.channel_names)
|
||||||
return view
|
return view
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -944,7 +944,7 @@ class AbstractReader(Imread, metaclass=ABCMeta):
|
|||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def __frame__(self, c, z, t): # Override this, return the frame at c, z, t
|
def __frame__(self, c, z, t): # Override this, return the frame at c, z, t
|
||||||
return np.random.randint(0, 255, self.shape['xy'])
|
return np.random.randint(0, 255, self.shape['yx'])
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def ome(self):
|
def ome(self):
|
||||||
@@ -989,7 +989,7 @@ class AbstractReader(Imread, metaclass=ABCMeta):
|
|||||||
instrument = self.ome.instruments[0] if self.ome.instruments else None
|
instrument = self.ome.instruments[0] if self.ome.instruments else None
|
||||||
image = self.ome.images[0]
|
image = self.ome.images[0]
|
||||||
pixels = image.pixels
|
pixels = image.pixels
|
||||||
self.shape = pixels.size_x, pixels.size_y, pixels.size_c, pixels.size_z, pixels.size_t
|
self.shape = pixels.size_y, pixels.size_x, pixels.size_c, pixels.size_z, pixels.size_t
|
||||||
self.dtype = pixels.type.value if dtype is None else dtype
|
self.dtype = pixels.type.value if dtype is None else dtype
|
||||||
self.pxsize = pixels.physical_size_x_quantity
|
self.pxsize = pixels.physical_size_x_quantity
|
||||||
try:
|
try:
|
||||||
@@ -1053,12 +1053,12 @@ class AbstractReader(Imread, metaclass=ABCMeta):
|
|||||||
self.exposuretime_s = [None if i is None else i.to(self.ureg.s).m for i in self.exposuretime]
|
self.exposuretime_s = [None if i is None else i.to(self.ureg.s).m for i in self.exposuretime]
|
||||||
|
|
||||||
if axes is None:
|
if axes is None:
|
||||||
self.axes = ''.join(i for i in 'cztxy' if self.shape[i] > 1)
|
self.axes = ''.join(i for i in 'cztyx' if self.shape[i] > 1)
|
||||||
elif axes.lower() == 'full':
|
elif axes.lower() == 'full':
|
||||||
self.axes = 'cztxy'
|
self.axes = 'cztyx'
|
||||||
else:
|
else:
|
||||||
self.axes = axes
|
self.axes = axes
|
||||||
self.slice = [np.arange(s, dtype=int) for s in self.shape.xyczt]
|
self.slice = [np.arange(s, dtype=int) for s in self.shape.yxczt]
|
||||||
|
|
||||||
m = self.extrametadata
|
m = self.extrametadata
|
||||||
if m is not None:
|
if m is not None:
|
||||||
|
|||||||
@@ -570,7 +570,7 @@ class Reader(AbstractReader, ABC):
|
|||||||
return ome
|
return ome
|
||||||
|
|
||||||
def __frame__(self, c=0, z=0, t=0):
|
def __frame__(self, c=0, z=0, t=0):
|
||||||
f = np.zeros(self.base.shape['xy'], self.dtype)
|
f = np.zeros(self.base.shape['yx'], self.dtype)
|
||||||
if (c, z, t) in self.filedict:
|
if (c, z, t) in self.filedict:
|
||||||
directory_entries = self.filedict[c, z, t]
|
directory_entries = self.filedict[c, z, t]
|
||||||
x_min = min([f.start[f.axes.index('X')] for f in directory_entries])
|
x_min = min([f.start[f.axes.index('X')] for f in directory_entries])
|
||||||
@@ -582,7 +582,7 @@ class Reader(AbstractReader, ABC):
|
|||||||
axes_min = [xy_min.get(ax, 0) for ax in directory_entry.axes]
|
axes_min = [xy_min.get(ax, 0) for ax in directory_entry.axes]
|
||||||
index = [slice(i - j - m, i - j + k)
|
index = [slice(i - j - m, i - j + k)
|
||||||
for i, j, k, m in zip(directory_entry.start, self.reader.start, tile.shape, axes_min)]
|
for i, j, k, m in zip(directory_entry.start, self.reader.start, tile.shape, axes_min)]
|
||||||
index = tuple(index[self.reader.axes.index(i)] for i in 'XY')
|
index = tuple(index[self.reader.axes.index(i)] for i in 'YX')
|
||||||
f[index] = tile.squeeze()
|
f[index] = tile.squeeze()
|
||||||
return f
|
return f
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ class Reader(AbstractReader, ABC):
|
|||||||
# in_idx = tuple(xyczt['xyczt'.find(i)] for i in self.axes)
|
# in_idx = tuple(xyczt['xyczt'.find(i)] for i in self.axes)
|
||||||
# print(f'{in_idx = }')
|
# print(f'{in_idx = }')
|
||||||
frame = self.array[:, :, c, z, t]
|
frame = self.array[:, :, c, z, t]
|
||||||
if self.axes.find('y') < self.axes.find('x'):
|
if self.axes.find('y') > self.axes.find('x'):
|
||||||
return frame.T
|
return frame.T
|
||||||
else:
|
else:
|
||||||
return frame
|
return frame
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ class Reader(AbstractReader, ABC):
|
|||||||
|
|
||||||
page = self.reader.pages[0]
|
page = self.reader.pages[0]
|
||||||
self.p_ndim = page.ndim # noqa
|
self.p_ndim = page.ndim # noqa
|
||||||
size_x = page.imagelength
|
size_y = page.imagelength
|
||||||
size_y = page.imagewidth
|
size_x = page.imagewidth
|
||||||
if self.p_ndim == 3:
|
if self.p_ndim == 3:
|
||||||
size_c = page.samplesperpixel
|
size_c = page.samplesperpixel
|
||||||
self.p_transpose = [i for i in [page.axes.find(j) for j in 'SYX'] if i >= 0] # noqa
|
self.p_transpose = [i for i in [page.axes.find(j) for j in 'SYX'] if i >= 0] # noqa
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "ndbioimage"
|
name = "ndbioimage"
|
||||||
version = "2024.3.2"
|
version = "2024.3.3"
|
||||||
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