- seqread: lazily read delta_t
- calculate timeinterval more efficiently - remove timeval field - bugfix in retrieving laser wavelenghts and powers - add series/pos to summary - cziread: better assign lightsources to channels
This commit is contained in:
@@ -17,12 +17,12 @@ from parfor import parfor
|
|||||||
from tiffwrite import IJTiffFile
|
from tiffwrite import IJTiffFile
|
||||||
from numbers import Number
|
from numbers import Number
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
from ndbioimage.transforms import Transform, Transforms
|
|
||||||
from ndbioimage.jvm import JVM
|
|
||||||
from typing import List
|
from typing import List
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from importlib.metadata import version
|
from importlib.metadata import version
|
||||||
from traceback import print_exc
|
from traceback import print_exc
|
||||||
|
from ndbioimage.transforms import Transform, Transforms
|
||||||
|
from ndbioimage.jvm import JVM
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -535,8 +535,9 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin, metaclass=ABCMeta):
|
|||||||
self.objective = find(instrument.objectives, id=self.ome.images[0].objective_settings.id)
|
self.objective = find(instrument.objectives, id=self.ome.images[0].objective_settings.id)
|
||||||
else:
|
else:
|
||||||
self.objective = None
|
self.objective = None
|
||||||
self.timeval = [find(image.pixels.planes, the_c=0, the_t=t, the_z=0).delta_t for t in range(self.shape['t'])]
|
t0 = find(image.pixels.planes, the_c=0, the_t=0, the_z=0).delta_t
|
||||||
self.timeinterval = np.diff(self.timeval).mean() if len(self.timeval) > 1 else 0
|
t1 = find(image.pixels.planes, the_c=0, the_t=self.shape['t'] - 1, the_z=0).delta_t
|
||||||
|
self.timeinterval = (t1 - t0) / (self.shape['t'] - 1) if self.shape['t'] > 1 else None
|
||||||
try:
|
try:
|
||||||
self.binning = [int(i) for i in image.pixels.channels[0].detector_settings.binning.value.split('x')]
|
self.binning = [int(i) for i in image.pixels.channels[0].detector_settings.binning.value.split('x')]
|
||||||
self.pxsize *= self.binning[0]
|
self.pxsize *= self.binning[0]
|
||||||
@@ -562,10 +563,10 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin, metaclass=ABCMeta):
|
|||||||
for channel in image.pixels.channels
|
for channel in image.pixels.channels
|
||||||
if channel.detector_settings
|
if channel.detector_settings
|
||||||
and find(instrument.detectors, id=channel.detector_settings.id).amplification_gain]
|
and find(instrument.detectors, id=channel.detector_settings.id).amplification_gain]
|
||||||
self.laserwavelengths = [(channel.emission_wavelength_quantity.to(self.ureg.nm).m,)
|
self.laserwavelengths = [(channel.excitation_wavelength_quantity.to(self.ureg.nm).m,)
|
||||||
for channel in pixels.channels if channel.emission_wavelength_quantity]
|
for channel in pixels.channels if channel.excitation_wavelength_quantity]
|
||||||
self.laserpowers = try_default(lambda channel: [(1 - channel.light_source_settings.attenuation,)
|
self.laserpowers = try_default(lambda: [(1 - channel.light_source_settings.attenuation,)
|
||||||
for channel in pixels.channels], [])
|
for channel in pixels.channels], [])
|
||||||
self.filter = try_default(lambda: [find(instrument.filter_sets, id=channel.filter_set_ref.id).model
|
self.filter = try_default(lambda: [find(instrument.filter_sets, id=channel.filter_set_ref.id).model
|
||||||
for channel in image.pixels.channels], None)
|
for channel in image.pixels.channels], None)
|
||||||
self.pxsize_um = None if self.pxsize is None else self.pxsize.to(self.ureg.um).m
|
self.pxsize_um = None if self.pxsize is None else self.pxsize.to(self.ureg.um).m
|
||||||
@@ -697,6 +698,7 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin, metaclass=ABCMeta):
|
|||||||
def summary(self):
|
def summary(self):
|
||||||
""" gives a helpful summary of the recorded experiment """
|
""" gives a helpful summary of the recorded experiment """
|
||||||
s = [f"path/filename: {self.path}",
|
s = [f"path/filename: {self.path}",
|
||||||
|
f"series/pos: {self.series}",
|
||||||
f"reader: {self.__class__.__module__.split('.')[-1]}",
|
f"reader: {self.__class__.__module__.split('.')[-1]}",
|
||||||
f"shape ({self.axes}):".ljust(15) + f"{' x '.join(str(i) for i in self.shape)}"]
|
f"shape ({self.axes}):".ljust(15) + f"{' x '.join(str(i) for i in self.shape)}"]
|
||||||
if self.pxsize_um:
|
if self.pxsize_um:
|
||||||
|
|||||||
@@ -360,10 +360,12 @@ class Reader(Imread, ABC):
|
|||||||
|
|
||||||
light_sources_settings = channel.find("LightSourcesSettings")
|
light_sources_settings = channel.find("LightSourcesSettings")
|
||||||
# no space in ome for multiple lightsources simultaneously
|
# no space in ome for multiple lightsources simultaneously
|
||||||
light_source_settings = light_sources_settings[0]
|
if len(light_sources_settings) > idx:
|
||||||
|
light_source_settings = light_sources_settings[idx]
|
||||||
|
else:
|
||||||
|
light_source_settings = light_sources_settings[0]
|
||||||
light_source_settings = model.LightSourceSettings(
|
light_source_settings = model.LightSourceSettings(
|
||||||
id="_".join([light_source_settings.find("LightSource").attrib["Id"]
|
id=light_source_settings.find("LightSource").attrib["Id"],
|
||||||
for light_source_settings in light_sources_settings]),
|
|
||||||
attenuation=float(text(light_source_settings.find("Attenuation"))),
|
attenuation=float(text(light_source_settings.find("Attenuation"))),
|
||||||
wavelength=float(text(light_source_settings.find("Wavelength"))),
|
wavelength=float(text(light_source_settings.find("Wavelength"))),
|
||||||
wavelength_unit=nm)
|
wavelength_unit=nm)
|
||||||
@@ -376,7 +378,7 @@ class Reader(Imread, ABC):
|
|||||||
color=model.simple_types.Color(text(channels_ds[channel.attrib["Id"]].find("Color"))),
|
color=model.simple_types.Color(text(channels_ds[channel.attrib["Id"]].find("Color"))),
|
||||||
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")),
|
emission_wavelength=text(channel.find("EmissionWavelength")),
|
||||||
excitation_wavelength=text(channel.find("ExcitationWavelength")),
|
excitation_wavelength=light_source_settings.wavelength,
|
||||||
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=text(channel.find("IlluminationType")),
|
illumination_type=text(channel.find("IlluminationType")),
|
||||||
light_source_settings=light_source_settings,
|
light_source_settings=light_source_settings,
|
||||||
|
|||||||
@@ -5,10 +5,35 @@ from ndbioimage import Imread
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from functools import cached_property
|
from functools import cached_property
|
||||||
from ome_types import model
|
from ome_types import model
|
||||||
|
from ome_types._base_type import quantity_property
|
||||||
from itertools import product
|
from itertools import product
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from abc import ABC
|
from abc import ABC
|
||||||
from parfor import pmap
|
|
||||||
|
|
||||||
|
def lazy_property(function, field, *arg_fields):
|
||||||
|
def lazy(self):
|
||||||
|
if self.__dict__.get(field) is None:
|
||||||
|
self.__dict__[field] = function(*[getattr(self, arg_field) for arg_field in arg_fields])
|
||||||
|
self.__fields_set__.add(field)
|
||||||
|
return self.__dict__[field]
|
||||||
|
return property(lazy)
|
||||||
|
|
||||||
|
|
||||||
|
class Plane(model.Plane):
|
||||||
|
""" Lazily retrieve delta_t from metadata """
|
||||||
|
def __init__(self, t0, file, **kwargs):
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
setattr(self.__class__, 'delta_t', lazy_property(self.get_delta_t, 'delta_t', 't0', 'file'))
|
||||||
|
setattr(self.__class__, 'delta_t_quantity', quantity_property('delta_t'))
|
||||||
|
self.__dict__['t0'] = t0
|
||||||
|
self.__dict__['file'] = file
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_delta_t(t0, file):
|
||||||
|
with tifffile.TiffFile(file) as tif:
|
||||||
|
info = yaml.safe_load(tif.pages[0].tags[50839].value['Info'])
|
||||||
|
return float((datetime.strptime(info["Time"], "%Y-%m-%d %H:%M:%S %z") - t0).seconds)
|
||||||
|
|
||||||
|
|
||||||
class Reader(Imread, ABC):
|
class Reader(Imread, ABC):
|
||||||
@@ -65,19 +90,10 @@ class Reader(Imread, ABC):
|
|||||||
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")))
|
||||||
|
|
||||||
def timeval_fun(i):
|
for c, z, t in product(range(size_c), range(size_z), range(size_t)):
|
||||||
with tifffile.TiffFile(self.filedict[i]) as tif:
|
|
||||||
info = yaml.safe_load(tif.pages[0].tags[50839].value['Info'])
|
|
||||||
return (datetime.strptime(info["Time"], "%Y-%m-%d %H:%M:%S %z") - t0).seconds
|
|
||||||
|
|
||||||
length = size_c * size_z * size_t
|
|
||||||
timeval = pmap(timeval_fun, product(range(size_c), range(size_z), range(size_t)), length=length,
|
|
||||||
serial=length <= 24, desc='Reading metadata')
|
|
||||||
|
|
||||||
for (c, z, t), time in zip(product(range(size_c), range(size_z), range(size_t)), timeval):
|
|
||||||
ome.images[0].pixels.planes.append(
|
ome.images[0].pixels.planes.append(
|
||||||
model.Plane(
|
Plane(t0, self.filedict[c, z, t],
|
||||||
the_c=c, the_z=z, the_t=t, exposure_time=metadata["Info"]["Exposure-ms"] / 1000, delta_t=time))
|
the_c=c, the_z=z, the_t=t, exposure_time=metadata["Info"]["Exposure-ms"] / 1000))
|
||||||
|
|
||||||
# compare channel names from metadata with filenames
|
# compare channel names from metadata with filenames
|
||||||
pattern_c = re.compile(r"img_\d{3,}_(.*)_\d{3,}$")
|
pattern_c = re.compile(r"img_\d{3,}_(.*)_\d{3,}$")
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "ndbioimage"
|
name = "ndbioimage"
|
||||||
version = "2023.7.0"
|
version = "2023.7.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