From 96ab3174d7db50b45c93d85d067b144dc01e2e35 Mon Sep 17 00:00:00 2001 From: Wim Pomp Date: Mon, 4 Sep 2023 10:26:10 +0200 Subject: [PATCH] - bugfix in czi metadata reader - cziread now gives empty frame if the frame wasn't saved in the file - astype accepts extra arguments, but does not use them - improved jvm handling - tifread dtype fix --- ndbioimage/__init__.py | 3 +- ndbioimage/jvm.py | 56 +++++++++++++++++++++-------------- ndbioimage/readers/cziread.py | 35 +++++++++++++--------- ndbioimage/readers/tifread.py | 7 ++++- pyproject.toml | 2 +- 5 files changed, 62 insertions(+), 41 deletions(-) diff --git a/ndbioimage/__init__.py b/ndbioimage/__init__.py index d736d2c..d66e3ec 100755 --- a/ndbioimage/__init__.py +++ b/ndbioimage/__init__.py @@ -346,7 +346,6 @@ class Shape(tuple): class Imread(np.lib.mixins.NDArrayOperatorsMixin): - def __new__(cls, path=None, *args, **kwargs): if cls is not Imread: return super().__new__(cls) @@ -955,7 +954,7 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin): def asarray(self): return self.__array__() - def astype(self, dtype): + def astype(self, dtype, *args, **kwargs): new = self.copy() new.dtype = dtype return new diff --git a/ndbioimage/jvm.py b/ndbioimage/jvm.py index 54fbea6..0c6494d 100644 --- a/ndbioimage/jvm.py +++ b/ndbioimage/jvm.py @@ -18,29 +18,37 @@ try: def __init__(self, jars=None): if not self.vm_started and not self.vm_killed: - jarpath = Path(__file__).parent / 'jars' - if jars is None: - jars = {} - for jar, src in jars.items(): - if not (jarpath / jar).exists(): - JVM.download(src, jarpath / jar) - classpath = [str(jarpath / jar) for jar in jars.keys()] + try: + jarpath = Path(__file__).parent / 'jars' + if jars is None: + jars = {} + for jar, src in jars.items(): + if not (jarpath / jar).exists(): + JVM.download(src, jarpath / jar) + classpath = [str(jarpath / jar) for jar in jars.keys()] - import jpype - jpype.startJVM(classpath=classpath) - import jpype.imports - from loci.common import DebugTools - from loci.formats import ImageReader - from loci.formats import ChannelSeparator - from loci.formats import FormatTools - from loci.formats import MetadataTools + import jpype + jpype.startJVM(classpath=classpath) + except Exception: + self.vm_started = False + else: + self.vm_started = True + try: + import jpype.imports + from loci.common import DebugTools + from loci.formats import ImageReader + from loci.formats import ChannelSeparator + from loci.formats import FormatTools + from loci.formats import MetadataTools - DebugTools.setRootLevel("ERROR") - self.vm_started = True - self.image_reader = ImageReader - self.channel_separator = ChannelSeparator - self.format_tools = FormatTools - self.metadata_tools = MetadataTools + DebugTools.setRootLevel("ERROR") + + self.image_reader = ImageReader + self.channel_separator = ChannelSeparator + self.format_tools = FormatTools + self.metadata_tools = MetadataTools + except Exception: + pass if self.vm_killed: raise Exception('The JVM was killed before, and cannot be restarted in this Python process.') @@ -51,8 +59,10 @@ try: dest.parent.mkdir(exist_ok=True) dest.write_bytes(request.urlopen(src).read()) - def kill_vm(self): - if self.vm_started and not self.vm_killed: + @classmethod + def kill_vm(cls): + self = cls._instance + if self is not None and self.vm_started and not self.vm_killed: import jpype jpype.shutdownJVM() self.vm_started = False diff --git a/ndbioimage/readers/cziread.py b/ndbioimage/readers/cziread.py index ef45ccd..fc2885c 100644 --- a/ndbioimage/readers/cziread.py +++ b/ndbioimage/readers/cziread.py @@ -58,6 +58,9 @@ class Reader(AbstractReader, ABC): def text(item, default=""): return default if item is None else item.text + def def_list(item): + return [] if item is None else item + ome = model.OME() metadata = tree.find("Metadata") @@ -99,7 +102,7 @@ class Reader(AbstractReader, ABC): model=tubelens.attrib["Name"], nominal_magnification=1.0)) # TODO: nominal_magnification - for light_source in instrument.find("LightSources"): + for light_source in def_list(instrument.find("LightSources")): if light_source.find("LightSourceType").find("Laser") is not None: ome.instruments[0].lasers.append( model.Laser( @@ -222,6 +225,9 @@ class Reader(AbstractReader, ABC): def text(item, default=""): return default if item is None else item.text + def def_list(item): + return [] if item is None else item + ome = model.OME() metadata = tree.find("Metadata") @@ -260,7 +266,7 @@ class Reader(AbstractReader, ABC): lens_na=float(text(objective.find("LensNA"))), nominal_magnification=float(text(objective.find("NominalMagnification"))))) - for light_source in instrument.find("LightSources"): + for light_source in def_list(instrument.find("LightSources")): if light_source.find("LightSourceType").find("Laser") is not None: ome.instruments[0].lasers.append( model.Laser( @@ -415,18 +421,19 @@ class Reader(AbstractReader, ABC): def __frame__(self, c=0, z=0, t=0): f = np.zeros(self.base.shape['xy'], self.dtype) - directory_entries = self.filedict[c, z, t] - x_min = min([f.start[f.axes.index('X')] for f in directory_entries]) - y_min = min([f.start[f.axes.index('Y')] for f in directory_entries]) - xy_min = {'X': x_min, 'Y': y_min} - for directory_entry in directory_entries: - subblock = directory_entry.data_segment() - tile = subblock.data(resize=True, order=0) - axes_min = [xy_min.get(ax, 0) for ax in directory_entry.axes] - 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)] - index = tuple(index[self.reader.axes.index(i)] for i in 'XY') - f[index] = tile.squeeze() + if (c, z, t) in self.filedict: + directory_entries = self.filedict[c, z, t] + x_min = min([f.start[f.axes.index('X')] for f in directory_entries]) + y_min = min([f.start[f.axes.index('Y')] for f in directory_entries]) + xy_min = {'X': x_min, 'Y': y_min} + for directory_entry in directory_entries: + subblock = directory_entry.data_segment() + tile = subblock.data(resize=True, order=0) + axes_min = [xy_min.get(ax, 0) for ax in directory_entry.axes] + 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)] + index = tuple(index[self.reader.axes.index(i)] for i in 'XY') + f[index] = tile.squeeze() return f @staticmethod diff --git a/ndbioimage/readers/tifread.py b/ndbioimage/readers/tifread.py index 7fcb233..0bb2fd9 100644 --- a/ndbioimage/readers/tifread.py +++ b/ndbioimage/readers/tifread.py @@ -44,6 +44,11 @@ class Reader(AbstractReader, ABC): else: pxsize = None + dtype = page.dtype.name + if dtype not in ('int8', 'int16', 'int32', 'uint8', 'uint16', 'uint32', + 'float', 'double', 'complex', 'double-complex', 'bit'): + dtype = 'float' + ome = model.OME() ome.instruments.append(model.Instrument(id='Instrument:0')) ome.instruments[0].objectives.append(model.Objective(id='Objective:0')) @@ -53,7 +58,7 @@ class Reader(AbstractReader, ABC): pixels=model.Pixels( id='Pixels:0', size_c=size_c, size_z=size_z, size_t=size_t, size_x=size_x, size_y=size_y, - dimension_order="XYCZT", type=page.dtype.name, physical_size_x=pxsize, physical_size_y=pxsize), + dimension_order="XYCZT", type=dtype, physical_size_x=pxsize, physical_size_y=pxsize), objective_settings=model.ObjectiveSettings(id="Objective:0"))) 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)) diff --git a/pyproject.toml b/pyproject.toml index 367d862..0373fb3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "ndbioimage" -version = "2023.8.2" +version = "2023.9.0" description = "Bio image reading, metadata and some affine registration." authors = ["W. Pomp "] license = "GPLv3"