- make cache size configurable

This commit is contained in:
Wim Pomp
2025-01-08 13:16:34 +01:00
parent e6d5ec0928
commit 8b280b3061
6 changed files with 55 additions and 43 deletions

View File

@@ -68,8 +68,8 @@ with Imread('image_file.tif', axes='cztyx') as im:
### Command line ### Command line
```ndbioimage --help```: show help ```ndbioimage --help```: show help
```ndbioimage image```: show metadata about image ```ndbioimage image```: show metadata about image
```ndbioimage image {name}.tif -r```: copy image into image.tif (replacing {name} with image), while registering channels ```ndbioimage image -w {name}.tif -r```: copy image into image.tif (replacing {name} with image), while registering channels
```ndbioimage image image.mp4 -C cyan lime red``` copy image into image.mp4 (z will be max projected), make channel colors cyan lime and red ```ndbioimage image -w image.mp4 -C cyan lime red``` copy image into image.mp4 (z will be max projected), make channel colors cyan lime and red
## Adding more formats ## Adding more formats
Readers for image formats subclass AbstractReader. When an image reader is imported, Imread will Readers for image formats subclass AbstractReader. When an image reader is imported, Imread will

View File

@@ -65,18 +65,18 @@ class DequeDict(OrderedDict):
self.maxlen = maxlen self.maxlen = maxlen
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
def __truncate__(self) -> None: def __setitem__(self, *args: Any, **kwargs: Any) -> None:
super().__setitem__(*args, **kwargs)
self.truncate()
def truncate(self) -> None:
if self.maxlen is not None: if self.maxlen is not None:
while len(self) > self.maxlen: while len(self) > self.maxlen:
self.popitem(False) self.popitem(False)
def __setitem__(self, *args: Any, **kwargs: Any) -> None:
super().__setitem__(*args, **kwargs)
self.__truncate__()
def update(self, *args: Any, **kwargs: Any) -> None: def update(self, *args: Any, **kwargs: Any) -> None:
super().update(*args, **kwargs) super().update(*args, **kwargs) # type: ignore
self.__truncate__() self.truncate()
def find(obj: Sequence[Any], **kwargs: Any) -> Any: def find(obj: Sequence[Any], **kwargs: Any) -> Any:
@@ -249,6 +249,7 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin, ABC):
tirfangle: Optional[list[float]] tirfangle: Optional[list[float]]
gain: Optional[list[float]] gain: Optional[list[float]]
pcf: Optional[list[float]] pcf: Optional[list[float]]
path: Path
__frame__: Callable[[int, int, int], np.ndarray] __frame__: Callable[[int, int, int], np.ndarray]
@staticmethod @staticmethod
@@ -331,8 +332,9 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin, ABC):
if hasattr(self, 'close'): if hasattr(self, 'close'):
self.close() self.close()
def __getitem__(self, n: int | Sequence[int] | slice | type(Ellipsis) | def __getitem__(self, n: int | Sequence[int] | Sequence[slice] | slice | type(Ellipsis) |
dict[str, int | Sequence[int] | slice | type(Ellipsis)]) -> Number | Imread | np.ndarray: dict[str, int | Sequence[int] | Sequence[slice] | slice | type(Ellipsis)]
) -> Number | Imread | np.ndarray:
""" slice like a numpy array but return an Imread instance """ """ slice like a numpy array but return an Imread instance """
if self.isclosed: if self.isclosed:
raise OSError('file is closed') raise OSError('file is closed')
@@ -380,7 +382,8 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin, ABC):
return new return new
def __getstate__(self) -> dict[str: Any]: def __getstate__(self) -> dict[str: Any]:
return {key: value for key, value in self.__dict__.items() if key not in self.do_not_pickle} return ({key: value for key, value in self.__dict__.items() if key not in self.do_not_pickle} |
{'cache_size': self.cache.maxlen})
def __len__(self) -> int: def __len__(self) -> int:
return self.shape[0] return self.shape[0]
@@ -390,10 +393,10 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin, ABC):
def __setstate__(self, state: dict[str, Any]) -> None: def __setstate__(self, state: dict[str, Any]) -> None:
""" What happens during unpickling """ """ What happens during unpickling """
self.__dict__.update(state) self.__dict__.update({key: value for key, value in state.items() if key != 'cache_size'})
if isinstance(self, AbstractReader): if isinstance(self, AbstractReader):
self.open() self.open()
self.cache = DequeDict(16) self.cache = DequeDict(state.get('cache_size', 16))
def __str__(self) -> str: def __str__(self) -> str:
return str(self.path) return str(self.path)
@@ -509,7 +512,7 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin, ABC):
yxczt = (slice(None), slice(None)) + idx yxczt = (slice(None), slice(None)) + idx
in_idx = tuple(yxczt['yxczt'.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) # type: ignore
for fun, ffun, initial in zip(funs, ffuns, initials)] for fun, ffun, initial in zip(funs, ffuns, initials)]
res = cfun(*initials) res = cfun(*initials)
res = (np.round(res) if dtype.kind in 'ui' else res).astype(p.sub('', dtype.name)) res = (np.round(res) if dtype.kind in 'ui' else res).astype(p.sub('', dtype.name))
@@ -543,7 +546,7 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin, ABC):
out_idx = tuple(yxczt['yxczt'.find(i)] for i in out_axes) out_idx = tuple(yxczt['yxczt'.find(i)] for i in out_axes)
in_idx = tuple(yxczt['yxczt'.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) # type: ignore
for fun, ffun, initial in zip(funs, ffuns, initials)]) for fun, ffun, initial in zip(funs, ffuns, initials)])
out[out_idx] = (np.round(res) if out.dtype.kind in 'ui' else res).astype(p.sub('', dtype.name)) out[out_idx] = (np.round(res) if out.dtype.kind in 'ui' else res).astype(p.sub('', dtype.name))
else: else:
@@ -556,12 +559,12 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin, ABC):
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],)
for tmp, fun, ffun, initial in zip(tmps, funs, ffuns, initials): for tmp, fun, ffun, initial in zip(tmps, funs, ffuns, initials):
tmp[out_idx] = fun((ffun(self[in_idx]),), 0, initial=initial, where=w) tmp[out_idx] = fun((ffun(self[in_idx]),), 0, initial=initial, where=w) # type: ignore
else: else:
w = where if where is None or isinstance(where, bool) else \ w = where if where is None or isinstance(where, bool) else \
(np.ones_like(where[in_idx]), where[in_idx]) (np.ones_like(where[in_idx]), where[in_idx])
for tmp, fun, ffun in zip(tmps, funs, ffuns): for tmp, fun, ffun in zip(tmps, funs, ffuns):
tmp[out_idx] = fun((tmp[out_idx], ffun(self[in_idx])), 0, where=w) tmp[out_idx] = fun((tmp[out_idx], ffun(self[in_idx])), 0, where=w) # type: ignore
out[...] = (np.round(cfun(*tmps)) if out.dtype.kind in 'ui' else out[...] = (np.round(cfun(*tmps)) if out.dtype.kind in 'ui' else
cfun(*tmps)).astype(p.sub('', dtype.name)) cfun(*tmps)).astype(p.sub('', dtype.name))
return out return out
@@ -606,7 +609,7 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin, ABC):
@property @property
def size(self) -> int: def size(self) -> int:
return np.prod(self.shape) return np.prod(self.shape) # type: ignore
@property @property
def shape(self) -> Shape: def shape(self) -> Shape:
@@ -665,7 +668,7 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin, ABC):
@property @property
def T(self) -> Imread: # noqa def T(self) -> Imread: # noqa
return self.transpose() return self.transpose() # type: ignore
@cached_property @cached_property
def timeseries(self) -> bool: def timeseries(self) -> bool:
@@ -782,7 +785,7 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin, ABC):
@wraps(np.ndarray.std) @wraps(np.ndarray.std)
def std(self, axis=None, dtype=None, out=None, ddof=0, keepdims=None, *, where=True): def std(self, axis=None, dtype=None, out=None, ddof=0, keepdims=None, *, where=True):
return self.var(axis, dtype, out, ddof, keepdims, where=where, std=True) return self.var(axis, dtype, out, ddof, keepdims, where=where, std=True) # type: ignore
@wraps(np.ndarray.sum) @wraps(np.ndarray.sum)
def sum(self, axis=None, dtype=None, out=None, keepdims=False, initial=None, where=True, **_): def sum(self, axis=None, dtype=None, out=None, keepdims=False, initial=None, where=True, **_):
@@ -845,7 +848,7 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin, ABC):
for i, e in zip('yxczt', (y, x, c, z, t))) for i, e in zip('yxczt', (y, x, c, z, t)))
d = np.empty((len(y), len(x), 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)[y][:, x] d[:, :, ci, zi, ti] = self.frame(cj, zj, tj)[y][:, x] # type: ignore
return d return d
def copy(self) -> View: def copy(self) -> View:
@@ -865,13 +868,14 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin, ABC):
# 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, self.frame_decorator) key = (c, z, t, self.transform, self.frame_decorator)
if key in self.cache: if self.cache.maxlen and key in self.cache:
self.cache.move_to_end(key) self.cache.move_to_end(key)
f = self.cache[key] f = self.cache[key]
else: else:
f = self.transform[self.channel_names[c], t].frame(self.__frame__(c, z, t)) f = self.transform[self.channel_names[c], t].frame(self.__frame__(c, z, t))
if self.frame_decorator is not None: if self.frame_decorator is not None:
f = self.frame_decorator(self, f, c, z, t) f = self.frame_decorator(self, f, c, z, t)
if self.cache.maxlen:
self.cache[key] = f self.cache[key] = f
if self.dtype is not None: if self.dtype is not None:
return f.copy().astype(self.dtype) return f.copy().astype(self.dtype)
@@ -942,7 +946,7 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin, ABC):
for plane in image.pixels.planes if plane.the_c == 0 and plane.the_t == 0]) for plane in image.pixels.planes if plane.the_c == 0 and plane.the_t == 0])
i = np.argsort(z[:, 1]) i = np.argsort(z[:, 1])
image.pixels.physical_size_z = np.nanmean(np.true_divide(*np.diff(z[i], axis=0).T)) * 1e6 image.pixels.physical_size_z = np.nanmean(np.true_divide(*np.diff(z[i], axis=0).T)) * 1e6
image.pixels.physical_size_z_unit = 'µm' image.pixels.physical_size_z_unit = 'µm' # type: ignore
except Exception: # noqa except Exception: # noqa
pass pass
return ome return ome
@@ -1015,7 +1019,7 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin, ABC):
frame = np.dstack([255 * frame * i for i in color]) frame = np.dstack([255 * frame * i for i in color])
return np.clip(np.round(frame), 0, 255).astype('uint8') return np.clip(np.round(frame), 0, 255).astype('uint8')
ab = list(zip(*[get_ab(i) for i in self.transpose('cztyx')])) ab = list(zip(*[get_ab(i) for i in self.transpose('cztyx')])) # type: ignore
colors = colors or ('r', 'g', 'b')[:self.shape['c']] + max(0, self.shape['c'] - 3) * ('w',) colors = colors or ('r', 'g', 'b')[:self.shape['c']] + max(0, self.shape['c'] - 3) * ('w',)
brightnesses = brightnesses or (1,) * self.shape['c'] brightnesses = brightnesses or (1,) * self.shape['c']
scale = scale or 1 scale = scale or 1
@@ -1027,7 +1031,7 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin, ABC):
outputdict={'-vcodec': 'libx264', '-preset': 'veryslow', '-pix_fmt': 'yuv420p', '-r': '7', outputdict={'-vcodec': 'libx264', '-preset': 'veryslow', '-pix_fmt': 'yuv420p', '-r': '7',
'-vf': f'setpts={25 / 7}*PTS,scale={shape_x}:{shape_y}:flags=neighbor'} '-vf': f'setpts={25 / 7}*PTS,scale={shape_x}:{shape_y}:flags=neighbor'}
) as movie: ) as movie:
im = self.transpose('tzcyx') im = self.transpose('tzcyx') # type: ignore
for ti in tqdm(t, desc='Saving movie', disable=not bar): for ti in tqdm(t, desc='Saving movie', disable=not bar):
movie.writeFrame(np.max([cframe(yx, c, a, b / s, scale) movie.writeFrame(np.max([cframe(yx, c, a, b / s, scale)
for yx, a, b, c, s in zip(im[ti].max('z'), *ab, colors, brightnesses)], 0)) for yx, a, b, c, s in zip(im[ti].max('z'), *ab, colors, brightnesses)], 0))
@@ -1061,7 +1065,7 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin, ABC):
n[i] = (n[i],) n[i] = (n[i],)
shape = [len(i) for i in n] shape = [len(i) for i in n]
with TransformTiff(self, fname.with_suffix('.tif'), pixel_type, with TransformTiff(self, fname.with_suffix('.tif'), dtype=pixel_type,
pxsize=self.pxsize_um, deltaz=self.deltaz_um, **kwargs) as tif: pxsize=self.pxsize_um, deltaz=self.deltaz_um, **kwargs) as tif:
for i, m in tqdm(zip(product(*[range(s) for s in shape]), product(*n)), # noqa for i, m in tqdm(zip(product(*[range(s) for s in shape]), product(*n)), # noqa
total=np.prod(shape), desc='Saving tiff', disable=not bar): total=np.prod(shape), desc='Saving tiff', disable=not bar):
@@ -1106,6 +1110,11 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin, ABC):
view.transform.adapt(view.frameoffset, view.shape.yxczt, view.channel_names) view.transform.adapt(view.frameoffset, view.shape.yxczt, view.channel_names)
return view return view
def set_cache_size(self, cache_size: int) -> None:
assert isinstance(cache_size, int) and cache_size >= 0
self.cache.maxlen = cache_size
self.cache.truncate()
@staticmethod @staticmethod
def split_path_series(path: Path | str) -> tuple[Path, int]: def split_path_series(path: Path | str) -> tuple[Path, int]:
if isinstance(path, str): if isinstance(path, str):
@@ -1320,12 +1329,13 @@ def main() -> None:
parser = ArgumentParser(description='Display info and save as tif') parser = ArgumentParser(description='Display info and save as tif')
parser.add_argument('-v', '--version', action='version', version=__version__) parser.add_argument('-v', '--version', action='version', version=__version__)
parser.add_argument('file', help='image_file', type=str, nargs='*') parser.add_argument('file', help='image_file', type=str, nargs='*')
parser.add_argument('-w', '--write', help='path to tif/movie out, {folder}, {name} and {ext} take this from file in', type=str, default=None) parser.add_argument('-w', '--write', help='path to tif/movie out, {folder}, {name} and {ext} take this from file in',
type=str, default=None)
parser.add_argument('-o', '--extract_ome', help='extract ome to xml file', action='store_true') parser.add_argument('-o', '--extract_ome', help='extract ome to xml file', action='store_true')
parser.add_argument('-r', '--register', help='register channels', action='store_true') parser.add_argument('-r', '--register', help='register channels', action='store_true')
parser.add_argument('-c', '--channel', help='channel', type=int, default=None) parser.add_argument('-c', '--channel', help='channel', type=int, default=None)
parser.add_argument('-z', '--zslice', help='z-slice', type=int, default=None) parser.add_argument('-z', '--zslice', help='z-slice', type=int, default=None)
parser.add_argument('-t', '--time', help='time', type=str, default=None) parser.add_argument('-t', '--time', help='time (frames) in python slicing notation', type=str, default=None)
parser.add_argument('-s', '--split', help='split channels', action='store_true') parser.add_argument('-s', '--split', help='split channels', action='store_true')
parser.add_argument('-f', '--force', help='force overwrite', action='store_true') parser.add_argument('-f', '--force', help='force overwrite', action='store_true')
parser.add_argument('-C', '--movie-colors', help='colors for channels in movie', type=str, nargs='*') parser.add_argument('-C', '--movie-colors', help='colors for channels in movie', type=str, nargs='*')

View File

@@ -332,7 +332,7 @@ class OmeParse:
model.Objective( model.Objective(
id=objective.attrib['Id'], id=objective.attrib['Id'],
model=self.text(objective.find('Manufacturer').find('Model')), model=self.text(objective.find('Manufacturer').find('Model')),
immersion=self.text(objective.find('Immersion')), immersion=self.text(objective.find('Immersion')), # type: ignore
lens_na=float(self.text(objective.find('LensNA'))), lens_na=float(self.text(objective.find('LensNA'))),
nominal_magnification=float(self.text(objective.find('NominalMagnification'))))) nominal_magnification=float(self.text(objective.find('NominalMagnification')))))
@@ -410,14 +410,14 @@ class OmeParse:
pixels=model.Pixels( pixels=model.Pixels(
id='Pixels:0', size_x=self.size_x, size_y=self.size_y, id='Pixels:0', size_x=self.size_x, size_y=self.size_y,
size_c=self.size_c, size_z=self.size_z, size_t=self.size_t, size_c=self.size_c, size_z=self.size_z, size_t=self.size_t,
dimension_order='XYCZT', type=pixel_type, dimension_order='XYCZT', type=pixel_type, # type: ignore
significant_bits=int(self.text(image.find('ComponentBitCount'))), significant_bits=int(self.text(image.find('ComponentBitCount'))),
big_endian=False, interleaved=False, metadata_only=True), big_endian=False, interleaved=False, metadata_only=True), # type: ignore
experimenter_ref=model.ExperimenterRef(id='Experimenter:0'), experimenter_ref=model.ExperimenterRef(id='Experimenter:0'),
instrument_ref=model.InstrumentRef(id='Instrument:0'), instrument_ref=model.InstrumentRef(id='Instrument:0'),
objective_settings=model.ObjectiveSettings( objective_settings=model.ObjectiveSettings(
id=objective_settings.find('ObjectiveRef').attrib['Id'], id=objective_settings.find('ObjectiveRef').attrib['Id'],
medium=self.text(objective_settings.find('Medium')), medium=self.text(objective_settings.find('Medium')), # type: ignore
refractive_index=float(self.text(objective_settings.find('RefractiveIndex')))), refractive_index=float(self.text(objective_settings.find('RefractiveIndex')))),
stage_label=model.StageLabel( stage_label=model.StageLabel(
name=f'Scene position #0', name=f'Scene position #0',
@@ -492,13 +492,13 @@ class OmeParse:
model.Channel( model.Channel(
id=f'Channel:{idx}', id=f'Channel:{idx}',
name=channel.attrib['Name'], name=channel.attrib['Name'],
acquisition_mode=self.text(channel.find('AcquisitionMode')), acquisition_mode=self.text(channel.find('AcquisitionMode')), # type: ignore
color=model.Color(self.text(self.channels_ds[channel.attrib['Id']].find('Color'), 'white')), color=model.Color(self.text(self.channels_ds[channel.attrib['Id']].find('Color'), 'white')),
detector_settings=model.DetectorSettings(id=detector.attrib['Id'], binning=binning), detector_settings=model.DetectorSettings(id=detector.attrib['Id'], binning=binning),
# emission_wavelength=text(channel.find('EmissionWavelength')), # TODO: fix # emission_wavelength=text(channel.find('EmissionWavelength')), # TODO: fix
excitation_wavelength=light_source_settings.wavelength, excitation_wavelength=light_source_settings.wavelength,
filter_set_ref=model.FilterSetRef(id=self.ome.instruments[0].filter_sets[filterset_idx].id), filter_set_ref=model.FilterSetRef(id=self.ome.instruments[0].filter_sets[filterset_idx].id),
illumination_type=self.text(channel.find('IlluminationType')), illumination_type=self.text(channel.find('IlluminationType')), # type: ignore
light_source_settings=light_source_settings, light_source_settings=light_source_settings,
samples_per_pixel=int(self.text(laser_scan_info.find('Averaging'))))) samples_per_pixel=int(self.text(laser_scan_info.find('Averaging')))))
elif self.version in ('1.1', '1.2'): elif self.version in ('1.1', '1.2'):
@@ -543,7 +543,7 @@ class OmeParse:
model.Channel( model.Channel(
id=f'Channel:{idx}', id=f'Channel:{idx}',
name=channel.attrib['Name'], name=channel.attrib['Name'],
acquisition_mode=self.text(channel.find('AcquisitionMode')).replace( acquisition_mode=self.text(channel.find('AcquisitionMode')).replace( # type: ignore
'SingleMoleculeLocalisation', 'SingleMoleculeImaging'), 'SingleMoleculeLocalisation', 'SingleMoleculeImaging'),
color=color, color=color,
detector_settings=model.DetectorSettings( detector_settings=model.DetectorSettings(
@@ -553,7 +553,7 @@ class OmeParse:
excitation_wavelength=self.try_default(float, None, excitation_wavelength=self.try_default(float, None,
self.text(channel.find('ExcitationWavelength'))), self.text(channel.find('ExcitationWavelength'))),
# filter_set_ref=model.FilterSetRef(id=ome.instruments[0].filter_sets[filterset_idx].id), # filter_set_ref=model.FilterSetRef(id=ome.instruments[0].filter_sets[filterset_idx].id),
illumination_type=self.text(channel.find('IlluminationType')), illumination_type=self.text(channel.find('IlluminationType')), # type: ignore
light_source_settings=light_source_settings, light_source_settings=light_source_settings,
samples_per_pixel=samples_per_pixel)) samples_per_pixel=samples_per_pixel))

View File

@@ -92,7 +92,8 @@ class Reader(AbstractReader, ABC):
pixels=model.Pixels( pixels=model.Pixels(
size_c=size_c, size_z=size_z, size_t=size_t, size_c=size_c, size_z=size_z, size_t=size_t,
size_x=metadata['Info']['Width'], size_y=metadata['Info']['Height'], size_x=metadata['Info']['Width'], size_y=metadata['Info']['Height'],
dimension_order='XYCZT', type=pixel_type, physical_size_x=pxsize, physical_size_y=pxsize, dimension_order='XYCZT', # type: ignore
type=pixel_type, physical_size_x=pxsize, physical_size_y=pxsize,
physical_size_z=metadata['Info']['Summary']['z-step_um']), physical_size_z=metadata['Info']['Summary']['z-step_um']),
objective_settings=model.ObjectiveSettings(id='Objective:0'))) objective_settings=model.ObjectiveSettings(id='Objective:0')))

View File

@@ -61,7 +61,8 @@ class Reader(AbstractReader, ABC):
pixels=model.Pixels( pixels=model.Pixels(
id='Pixels:0', id='Pixels:0',
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=dtype, physical_size_x=pxsize, physical_size_y=pxsize), dimension_order='XYCZT', type=dtype, # type: ignore
physical_size_x=pxsize, physical_size_y=pxsize),
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=interval_t * t)) ome.images[0].pixels.planes.append(model.Plane(the_c=c, the_z=z, the_t=t, delta_t=interval_t * t))

View File

@@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "ndbioimage" name = "ndbioimage"
version = "2024.10.0" version = "2025.1.0"
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"
@@ -16,13 +16,13 @@ numpy = ">=1.20.0"
pandas = "*" pandas = "*"
tifffile = "*" tifffile = "*"
czifile = "2019.7.2" czifile = "2019.7.2"
tiffwrite = ">=2024.10.4" tiffwrite = ">=2024.12.1"
ome-types = ">=0.4.0" ome-types = ">=0.4.0"
pint = "*" pint = "*"
tqdm = "*" tqdm = "*"
lxml = "*" lxml = "*"
pyyaml = "*" pyyaml = "*"
parfor = ">=2024.9.2" parfor = ">=2025.1.0"
JPype1 = "*" JPype1 = "*"
SimpleITK-SimpleElastix = [ SimpleITK-SimpleElastix = [
{ version = "*", python = "<3.12" }, { version = "*", python = "<3.12" },