Writing with tifffile never saves a completely flawless ome.tiff

Hi,

I am basically setting up a deconvolution pipeline (each nd2 file is >1.5TB) of my live cell imaging data.

I managed to make .ome.tiffs (metadata and tiff files) that are successfully opened in ImageJ, however I still have an error while populating and reading the metadata (that makes a higher parse time and having into account the size of the files I would like to fix this).

The last example in the code: test4.ome.tiff has ImageJ type hyperstack loading without errors, but then I can’t save the ome.xml type metadata into it.

  • If I drag a file into ImageJ I only have on XY frame.
    I have this in console:

[ WARNING] Image ID ‘Image:0’: missing plane #0. Using TiffReader to determine the number of planes.

  • If I use the bioformats plugin then the whole stack is correctly loaded I have T,C,Z in the proper order.
    But I still have this message:

First line outputs when I call bioformats plugin and load the file(all other messages happen when I click okay to read it)

[WARNING] Image ID ‘Image:0’: missing plane #0. Using TiffReader to determine the number of planes.
[WARN] Image ID ‘Image:0’: missing plane #0
[WARN] Image ID ‘Image:0’: missing plane #1
[WARN] Image ID ‘Image:0’: missing plane #2
[WARN] Image ID ‘Image:0’: missing plane #3
[WARN] Image ID ‘Image:0’: missing plane #4
[WARN] Image ID ‘Image:0’: missing plane #5
[WARN] Image ID ‘Image:0’: missing plane #6
[WARN] Image ID ‘Image:0’: missing plane #7
[WARN] Image ID ‘Image:0’: missing plane #8
[WARN] Image ID ‘Image:0’: missing plane #9
[WARN] Image ID ‘Image:0’: missing plane #10
[WARN] Image ID ‘Image:0’: missing plane #11
[WARN] Image ID ‘Image:0’: missing plane #12
[WARN] Image ID ‘Image:0’: missing plane #13
[WARN] Image ID ‘Image:0’: missing plane #14
[WARN] Image ID ‘Image:0’: missing plane #15
[WARN] Image ID ‘Image:0’: missing plane #16
[WARN] Image ID ‘Image:0’: missing plane #17
[WARN] Image ID ‘Image:0’: missing plane #18
[WARN] Image ID ‘Image:0’: missing plane #19
[WARN] Image ID ‘Image:0’: missing plane #20
[WARN] Image ID ‘Image:0’: missing plane #21
[WARN] Using TiffReader to determine the number of planes.
Reading IFDs
Populating metadata
Checking comment style
Populating OME metadata
Reading IFDs
Populating metadata
Checking comment style
Populating OME metadata

This is a snippet code exemplifying different writing examples (I need to write each YX or ZYX or CZYC one by one as it’s impossible to have the whole data loaded into my RAM).

import numpy as np
import bioformats.omexml as ome
import tifffile as tf
import sys


def writeplanes(pixel, SizeT=1, SizeZ=1, SizeC=1, order='TZCYX'
            , verbose=False):

    if order == 'TZCYX':

        p.DimensionOrder = ome.DO_XYCZT
        counter = 0
        for t in range(SizeT):
            for z in range(SizeZ):
                for c in range(SizeC):

                    if verbose:
                        print('Write PlaneTable: ', t, z, c),
                        sys.stdout.flush()

                    pixel.Plane(counter).TheT = t
                    pixel.Plane(counter).TheZ = z
                    pixel.Plane(counter).TheC = c
                    counter = counter + 1

    return pixel


# Dimension TZCXY
SizeT = 1
SizeZ = 11
SizeC = 2
SizeX = 2044
SizeY = 2044
Series = 0


scalex = 0.10833
scaley = scalex
scalez = 0.3
pixeltype = 'uint16'
dimorder = 'TZCYX'
output_file = r'/tmp/stack.ome.tiff' #this does nothing in this example

# create numpy array with correct order

# Getting metadata info
omexml = ome.OMEXML()
omexml.image(Series).Name = output_file
p = omexml.image(Series).Pixels
#p.ID = 0
p.SizeX = SizeX
p.SizeY = SizeY
p.SizeC = SizeC
p.SizeT = SizeT
p.SizeZ = SizeZ
p.PhysicalSizeX = np.float(scalex)
p.PhysicalSizeY = np.float(scaley)
p.PhysicalSizeZ = np.float(scalez)
p.PixelType = pixeltype
p.channel_count = SizeC
p.plane_count = SizeZ * SizeT * SizeC
p = writeplanes(p, SizeT=SizeT, SizeZ=SizeZ, SizeC=SizeC, order=dimorder)

for c in range(SizeC):
    if pixeltype == 'unit8':
        p.Channel(c).SamplesPerPixel = 1
    if pixeltype == 'unit16':
        p.Channel(c).SamplesPerPixel = 2


omexml.structured_annotations.add_original_metadata(
            ome.OM_SAMPLES_PER_PIXEL, str(SizeC))

# Converting to omexml
xml = omexml.to_xml()


img5d = np.random.randn(
        SizeT, SizeZ, SizeC, SizeY, SizeX).astype(np.uint16)

# ~ write file and save OME-XML as description
tf.imwrite(r'/tmp/test1.ome.tiff', img5d#,
    , description=xml)


with tf.TiffWriter('/tmp/test2.ome.tiff'
               #, bigtiff=True
               #, imagej=True
                      ) as tif:
    for t in range(SizeT):
        for z in range(SizeZ):
            for c in range(SizeC):      
                # ~ print(img5d[t,z,c,:,:].shape)   # -> (2044, 2044)
                tif.save(img5d[t,z,c,:,:]
            #                     ,shape=res.shape

                        #,resolution= (.1083,0.1083,3)
                         , description = xml
                        , photometric='minisblack'
                        #, datetime= True
                        , metadata={'axes': 'TZCYX'
                            , 'DimensionOrder' : 'TZCYX'
                            , 'Resolution': 0.10833}
                            )

with tf.TiffWriter('/tmp/test3.ome.tiff'
               #, bigtiff=True
               #, imagej=True
                      ) as tif:
    for t in range(SizeT):
        # ~ print(img5d[t,z,c,:,:].shape)   # -> (2044, 2044)
        tif.save(img5d[t,:,:,:,:]
    #                     ,shape=res.shape

                #,resolution= (.1083,0.1083,3)
                 , description = xml
                , photometric='minisblack'
                #, datetime= True
                , metadata={'axes': 'TZCYX'
                    , 'DimensionOrder' : 'TZCYX'
                    , 'Resolution': 0.10833}
                    )

with tf.TiffWriter('/tmp/test4.ome.tiff'
               #, bigtiff=True
               , imagej=True
                      ) as tif:
    for t in range(SizeT):
        # ~ print(img5d[t,z,c,:,:].shape)   # -> (2044, 2044)
        tif.save(img5d[t,:,:,:,:]
    #                     ,shape=res.shape

                #,resolution= (.1083,0.1083,3)
                 , description = xml
                , photometric='minisblack'
                #, datetime= True
                , metadata={'axes': 'TZCYX'
                    , 'DimensionOrder' : 'TZCYX'
                    , 'Resolution': 0.10833}
                    )

this example using aicsimageio to handle the ome xml solves the problem (python-bioformats also writes tiffdata but I’d have to manually create the loop in a new function).

This works!
changed to : import aicsimageio.vendor.omexml as ome
and added after the planes creation in the pixel: p.populate_TiffData()

I hope it is useful to somebody else!

import numpy as np
import aicsimageio.vendor.omexml as ome
import tifffile as tf
import sys


def writeplanes(pixel, SizeT=1, SizeZ=1, SizeC=1, order='TZCYX'
            , verbose=False):

    if order == 'TZCYX':

        p.DimensionOrder = ome.DO_XYCZT
        counter = 0
        for t in range(SizeT):
            for z in range(SizeZ):
                for c in range(SizeC):

                    if verbose:
                        print('Write PlaneTable: ', t, z, c),
                        sys.stdout.flush()

                    pixel.Plane(counter).TheT = t
                    pixel.Plane(counter).TheZ = z
                    pixel.Plane(counter).TheC = c
                    counter = counter + 1

    return pixel


# Dimension TZCXY
SizeT = 3
SizeZ = 11
SizeC = 2
SizeX = 2044
SizeY = 2044
Series = 0


scalex = 0.10833
scaley = scalex
scalez = 0.3
pixeltype = 'uint16'
dimorder = 'TZCYX'
output_file = r'/tmp/stack.ome.tiff' #this does nothing in this example

# create numpy array with correct order

# Getting metadata info
omexml = ome.OMEXML()
omexml.image(Series).Name = output_file
p = omexml.image(Series).Pixels
#p.ID = 0
p.SizeX = SizeX
p.SizeY = SizeY
p.SizeC = SizeC
p.SizeT = SizeT
p.SizeZ = SizeZ
p.PhysicalSizeX = np.float(scalex)
p.PhysicalSizeY = np.float(scaley)
p.PhysicalSizeZ = np.float(scalez)
p.PixelType = pixeltype
p.channel_count = SizeC
p.plane_count = SizeZ * SizeT * SizeC
p = writeplanes(p, SizeT=SizeT, SizeZ=SizeZ, SizeC=SizeC, order=dimorder)

for c in range(SizeC):
    if pixeltype == 'unit8':
        p.Channel(c).SamplesPerPixel = 1
    if pixeltype == 'unit16':
        p.Channel(c).SamplesPerPixel = 2

p.populate_TiffData()
omexml.structured_annotations.add_original_metadata(
            ome.OM_SAMPLES_PER_PIXEL, str(SizeC))

# Converting to omexml
xml = omexml.to_xml()


img5d = np.random.randn(
        SizeT, SizeZ, SizeC, SizeY, SizeX).astype(np.uint16)

# ~ write file and save OME-XML as description
tf.imwrite(r'/tmp/test1.ome.tiff', img5d ,bigtiff=True, imagej=False
, metadata=None, contiguous=False
    , description=xml )


with tf.TiffWriter('/tmp/test2.ome.tiff'
               #, bigtiff=True
               #, imagej=Truea
                      ) as tif:
    for t in range(SizeT):
        for z in range(SizeZ):
            for c in range(SizeC): 
                print(img5d[t,z,c,:,:].shape)
                # ~ print(img5d[t,z,c,:,:].shape)   # -> (2044, 2044)
                tif.save(img5d[t,z,c,:,:]
            #                     ,shape=res.shape

                        #,resolution= (.1083,0.1083,3)
                         , description = xml
                        , photometric='minisblack'
                        #, datetime= True
                        , metadata={'axes': 'TZCYX'
                            , 'DimensionOrder' : 'TZCYX'
                            , 'Resolution': 0.10833}
                            )

with tf.TiffWriter('/tmp/test3.ome.tiff'
               #, bigtiff=True
               #, imagej=True
                      ) as tif:
    for t in range(SizeT):
        # ~ print(img5d[t,z,c,:,:].shape)   # -> (2044, 2044)
        print(img5d[t,:,:,:,:].shape)
        tif.save(img5d[t,:,:,:,:]
    #                     ,shape=res.shape

                #,resolution= (.1083,0.1083,3)
                 , description = xml
                , photometric='minisblack'
                #, datetime= True
                , metadata={'axes': 'TZCYX'
                    , 'DimensionOrder' : 'TZCYX'
                    , 'Resolution': 0.10833}
                    )

with tf.TiffWriter('/tmp/test4.ome.tiff'
               #, bigtiff=True
               , imagej=True
                      ) as tif:
    for t in range(SizeT):
        # ~ print(img5d[t,z,c,:,:].shape)   # -> (2044, 2044)
        tif.save(img5d[t,:,:,:,:]
    #                     ,shape=res.shape

                #,resolution= (.1083,0.1083,3)
                 , description = xml
                , photometric='minisblack'
                #, datetime= True
                ,metadata = {'channels':SizeC ,'slices':SizeT ,
                'frames':SizeZ * SizeT * SizeC
                ,'hyperstack':True ,'loop':False
                , 'Resolution': 0.10833}
                # ~ , metadata={'axes': 'TZCYX'
                    # ~ , 'DimensionOrder' : 'TZCYX'
                    # ~ , 'Resolution': 0.10833}
                    )



1 Like