CellProfiler / python-bioformats

Read and write life sciences file formats
Other
131 stars 45 forks source link

What's the proper way to write 5D data? #106

Open morganrcu opened 6 years ago

morganrcu commented 6 years ago

Hi,

I'm trying the following snippet to try to understand how 5D data should be written to a ome.tif file using python bioformats:

import javabridge
import bioformats as bf
import numpy as np
javabridge.start_vm(class_path=bf.JARS,run_headless=True)

NT=10
NC=2
NZ=4

NX=16
NY=16

output_path='./out.ome.tif'

for t in range(NT):
    for z in range(NZ):
        for c in range(NC):
            frame=np.random.randn(NX,NY,1,1,1).astype(np.uint16)
            bf.write_image('./out.ome.tif', pixels=frame, pixel_type=bf.PT_UINT16, c=c, t=t, z=z, size_c=NC, size_t=NT, size_z=NZ)

xml_metadata = bf.get_omexml_metadata(path=output_path)
metadata = bf.OMEXML(xml_metadata)

NXp = metadata.image().Pixels.SizeX
NYp = metadata.image().Pixels.SizeY
NZp = metadata.image().Pixels.SizeZ
NCp = metadata.image().Pixels.SizeC
NTp = metadata.image().Pixels.SizeT

print(NXp,NYp,NZp,NCp,NTp)

assert(NXp==NX)
assert(NYp==NY)
assert(NZp==NZ)
assert(NCp==NC)
assert(NTp==NT)

javabridge.kill_vm()

producing the output (debug messages discarded):

16 16 1 1 1 assert(NZp==NZ) AssertionError

The metadata of the produced file does not properly store the correct number of planes, timepoints and channels. What's wrong with my way of writing the data?

Thank you very much, Rodrigo

okdzhimiev commented 6 years ago

Remove extra dot from the filename and it will work - e.g. outcome.tiff

View with the latest Fiji (ImageJ 1.52d) ImageJ 1.50d (which is installed by default in my os) displays the stack incorrectly for some reason.

sebi06 commented 5 years ago

Ok. ans the solution is then to rename the file back to *.ome.tiff?

okdzhimiev commented 5 years ago

Yes, rename until this little bug gets fixed.

A better alternative solution (vs depending on javabridge & bioformats) would be checking out and adapting:

sebi06 commented 5 years ago

Thx. So my script now looks like below. Any hints or tips on how to add OME metadata to to file while writing it?

import javabridge as jv
import bioformats as bf
import numpy as np

jv.start_vm(class_path=bf.JARS, run_headless=True)
SizeT = 10
SizeZ = 23
SizeC = 2
SizeX = 217
SizeY = 94

output_file = r"stackome.tiff"
img5d = np.random.randn(SizeT, SizeZ, SizeC, SizeY, SizeX).astype(np.uint16)

for t in range(SizeT):
    for z in range(SizeZ):
        for c in range(SizeC):

            img2write = img5d[t, z, c, :, :]
            frame = np.uint16(img2write[:, :, np.newaxis, np.newaxis, np.newaxis])
            print(frame.shape)
            bf.write_image(output_file, pixels=frame,pixel_type=bf.PT_UINT16,t=t,z=z,c=c,size_t=SizeT,size_z=SizeZ,size_c=SizeC)

jv.kill_vm()
okdzhimiev commented 5 years ago

Have a look at bioformats/formatwriter.py.

sebi06 commented 5 years ago

I did but I ran into an issue where the Z-dimension was always missing. Now I use:

import bioformats.omexml as ome
import tifffile
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 = 4
SizeC = 2
SizeX = 217
SizeY = 94
Series = 0

scalex = 0.1
scaley = scalex
scalez = 0.5
pixeltype = 'uint16'
dimorder = 'TZCYX'
output_file = r'stack.ome.tiff'

# create numpy array with correct order
img5d = np.random.randn(SizeT, SizeZ, SizeC, SizeY, SizeX).astype(np.uint16)

# 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()

# write file and save OME-XML as description
tifffile.imwrite(output_file, img5d, metadata={'axes': dimorder}, description=xml)
okdzhimiev commented 5 years ago

Looks good. Problem solved?