Skip to content

Commit

Permalink
Improved tiff metadata extraction, improved combining images
Browse files Browse the repository at this point in the history
  • Loading branch information
folterj committed Feb 13, 2024
1 parent 9455bdf commit 36e1575
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 33 deletions.
20 changes: 16 additions & 4 deletions OmeSliCC/OmeSource.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ class OmeSource:
"""#bits for all pages"""
channels: list
"""channel information for all image channels"""
position: list
"""source position information"""

default_physical_unit = 'µm'

def __init__(self):
self.metadata = {}
Expand Down Expand Up @@ -76,14 +80,22 @@ def _get_ome_metadate(self):
self.source_pixel_size = []
size = float(pixels.get('PhysicalSizeX', 0))
if size > 0:
self.source_pixel_size.append((size, pixels.get('PhysicalSizeXUnit', 'µm')))
self.source_pixel_size.append((size, pixels.get('PhysicalSizeXUnit', self.default_physical_unit)))
size = float(pixels.get('PhysicalSizeY', 0))
if size > 0:
self.source_pixel_size.append((size, pixels.get('PhysicalSizeYUnit', 'µm')))
self.source_pixel_size.append((size, pixels.get('PhysicalSizeYUnit', self.default_physical_unit)))
size = float(pixels.get('PhysicalSizeZ', 0))
if size > 0:
self.source_pixel_size.append((size, pixels.get('PhysicalSizeZUnit', 'µm')))
self.source_pixel_size.append((size, pixels.get('PhysicalSizeZUnit', self.default_physical_unit)))

position = []
for plane in ensure_list(pixels.get('Plane', [])):
position = [(plane.get('PositionX'), plane.get('PositionXUnit')),
(plane.get('PositionY'), plane.get('PositionYUnit')),
(plane.get('PositionZ'), plane.get('PositionZUnit'))]
c, z, t = plane.get('TheC'), plane.get('TheZ'), plane.get('TheT')

self.position = position
self.source_mag = 0
objective_id = images.get('ObjectiveSettings', {}).get('ID', '')
for objective in ensure_list(self.metadata.get('Instrument', {}).get('Objective', [])):
Expand Down Expand Up @@ -180,7 +192,7 @@ def get_channels(self) -> list:

def get_size(self) -> tuple:
# size at target pixel size
return np.round(np.multiply(self.sizes[self.best_level], self.best_factor)).astype(int)
return tuple(np.round(np.multiply(self.sizes[self.best_level], self.best_factor)).astype(int))

def get_size_xyzct(self) -> tuple:
xyzct = list(self.sizes_xyzct[self.best_level]).copy()
Expand Down
6 changes: 3 additions & 3 deletions OmeSliCC/OmeroSource.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,9 @@ def __init__(self,

def _find_metadata(self):
image_object = self.image_object
self.source_pixel_size = [(get_default(image_object.getPixelSizeX(), 0), 'µm'),
(get_default(image_object.getPixelSizeY(), 0), 'µm'),
(get_default(image_object.getPixelSizeZ(), 0), 'µm')]
self.source_pixel_size = [(get_default(image_object.getPixelSizeX(), 0), self.default_physical_unit),
(get_default(image_object.getPixelSizeY(), 0), self.default_physical_unit),
(get_default(image_object.getPixelSizeZ(), 0), self.default_physical_unit)]
objective_settings = image_object.getObjectiveSettings()
if objective_settings:
self.source_mag = objective_settings.getObjective().getNominalMagnification()
Expand Down
34 changes: 19 additions & 15 deletions OmeSliCC/TiffSource.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,12 @@ def __init__(self,
self.metadata = tiff.imagej_metadata
elif self.first_page.description:
self.metadata = desc_to_dict(self.first_page.description)
else:
self.metadata = tags_to_dict(self.first_page.tags)
if 'FEI_TITAN' in self.metadata:
metadata = tifffile.xml2dict(self.metadata.pop('FEI_TITAN'))
if 'FeiImage' in metadata:
metadata = metadata['FeiImage']
self.metadata.update(metadata)
self.tags = tags_to_dict(self.first_page.tags)
if 'FEI_TITAN' in self.tags:
metadata = tifffile.xml2dict(self.tags.pop('FEI_TITAN'))
if 'FeiImage' in metadata:
metadata = metadata['FeiImage']
self.metadata.update(metadata)

if tiff.series:
self.dimension_order = tiff.series[0].axes
Expand Down Expand Up @@ -120,8 +119,11 @@ def _find_metadata(self):

# from imageJ metadata
pixel_size_z = None
if len(pixel_size) == 0 and self.metadata is not None and 'spacing' in self.metadata:
if self.metadata is not None and 'unit' in self.metadata:
pixel_size_unit = self.metadata.get('unit', '')
if pixel_size_unit == 'micron':
pixel_size_unit = self.default_physical_unit
if len(pixel_size) == 0 and self.metadata is not None and 'spacing' in self.metadata:
pixel_size_z = (self.metadata['spacing'], pixel_size_unit)
# from description
if len(pixel_size) < 2 and 'pixelWidth' in self.metadata:
Expand All @@ -130,26 +132,27 @@ def _find_metadata(self):
pixel_info = self.metadata['pixelHeight']
pixel_size.append((pixel_info['value'], pixel_info['unit']))
if len(pixel_size) < 2 and 'MPP' in self.metadata:
pixel_size.append((self.metadata['MPP'], 'µm'))
pixel_size.append((self.metadata['MPP'], 'µm'))
pixel_size.append((self.metadata['MPP'], self.default_physical_unit))
pixel_size.append((self.metadata['MPP'], self.default_physical_unit))
# from page TAGS
if len(pixel_size) < 2:
if pixel_size_unit == '':
pixel_size_unit = self.metadata.get('ResolutionUnit', '')
pixel_size_unit = self.tags.get('ResolutionUnit', '')
if isinstance(pixel_size_unit, Enum):
pixel_size_unit = pixel_size_unit.name
pixel_size_unit = pixel_size_unit.lower()
if pixel_size_unit == 'none':
pixel_size_unit = ''
res0 = convert_rational_value(self.metadata.get('XResolution'))
res0 = convert_rational_value(self.tags.get('XResolution'))
if res0 is not None and res0 != 0:
pixel_size.append((1 / res0, pixel_size_unit))
res0 = convert_rational_value(self.metadata.get('YResolution'))
res0 = convert_rational_value(self.tags.get('YResolution'))
if res0 is not None and res0 != 0:
pixel_size.append((1 / res0, pixel_size_unit))

xpos = convert_rational_value(self.metadata.get('XPosition'))
ypos = convert_rational_value(self.metadata.get('YPosition'))
position = []
xpos = convert_rational_value(self.tags.get('XPosition'))
ypos = convert_rational_value(self.tags.get('YPosition'))
if xpos is not None and ypos is not None:
position = [(xpos, pixel_size_unit), (ypos, pixel_size_unit)]

Expand All @@ -168,6 +171,7 @@ def _find_metadata(self):
self.source_pixel_size = pixel_size
self.source_mag = mag
self.channels = channels
self.position = position

def get_source_dask(self):
return [da.from_zarr(self.tiff.aszarr(level=level)) for level in range(len(self.sizes))]
Expand Down
31 changes: 20 additions & 11 deletions OmeSliCC/conversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import numpy as np
import os
from PIL import Image
import psutil
from tifffile import TiffWriter, TIFF, PHOTOMETRIC

from OmeSliCC import Omero
Expand Down Expand Up @@ -140,22 +141,28 @@ def combine_images(sources: list[OmeSource], params: dict):
ome = ('ome' in output_format)
filetitle = get_filetitle(source_ref).rstrip('.ome')
output_filename = str(os.path.join(output_folder, filetitle + '_combined.' + output_format))

new_source = OmeSource()
new_source.source_reference = output_filename
new_source.target_pixel_size = source0.get_pixel_size()
new_source.position = source0.position
new_source.channels = channels
new_source.sizes = [source0.get_size()]
sizes_xyzc = list(source0.get_size_xyzct())
sizes_xyzc[3] = nchannels
new_source.sizes_xyzct = [tuple(sizes_xyzc)]
new_source.pixel_types = source0.pixel_types
new_source.pixel_nbits = source0.pixel_nbits
new_source.best_level, new_source.best_factor, new_source.full_factor = 0, 1, 1
new_source.source_mag = source0.source_mag
new_source.output_dimension_order = source0.output_dimension_order

if 'zar' in output_format:
new_source = OmeZarrSource(source_ref, source0.get_pixel_size())
new_source.channels = channels
size = list(new_source.sizes_xyzct[0])
size[3] = nchannels
new_source.sizes_xyzct[0] = size
if 'ome.' in output_format:
save_image_as_ome_zarr(new_source, image, output_filename, output_params)
else:
save_image_as_zarr(new_source, image, output_filename, output_params)
elif 'tif' in output_format:
new_source = TiffSource(source_ref, source0.get_pixel_size())
new_source.channels = channels
size = list(new_source.sizes_xyzct[0])
size[3] = nchannels
new_source.sizes_xyzct[0] = size
save_image_as_tiff(new_source, image, output_filename, output_params, ome=ome)
else:
save_image(image, output_filename, output_params)
Expand Down Expand Up @@ -239,7 +246,9 @@ def save_tiff(filename: str, image: np.ndarray, metadata: dict = None, xml_metad
dimension_order: str = 'yxc',
resolution: tuple = None, resolution_unit: str = None, tile_size: tuple = None, compression: [] = None,
combine_rgb=True, pyramid_sizes_add: list = []):
image = np.asarray(image) # pre-computing is way faster than dask saving/scaling
image_size = image.size * image.itemsize
if image_size < psutil.virtual_memory().total:
image = np.asarray(image) # pre-computing is way faster than dask saving/scaling
x_index = dimension_order.index('x')
y_index = dimension_order.index('y')
size = image.shape[x_index], image.shape[y_index]
Expand Down
1 change: 1 addition & 0 deletions OmeSliCC/ome_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ def create_ome_metadata(source: OmeSource,
if len(pixel_size) > 2 and pixel_size[2][1] != '':
pixels['@PhysicalSizeZUnit'] = pixel_size[2][1]

# TODO: create plane metadata if not exists
planes = ensure_list(pixels0.get('Plane', []))
if len(planes) > 0:
pixels['Plane'] = planes
Expand Down

0 comments on commit 36e1575

Please sign in to comment.