Search code examples
pythontiffimagejimagej-hyperstack

Converting 32-bit TIFF to 8-bit TIFF while retaining metadata and tags in python?


I would like to convert several TIFF files with 32-bit pixel depth into 8-bit pixel depth TIFFs while retaining metadata and TIFF tags.

The 32-bit TIFFs are four-dimensional ImageJ-hyperstacks with TZYX axes (i.e. time, z-depth, y-coordinate, x-coordinate) and values in the range of [0, 1].

I can convert to 8-bit and copy over the metadata (using a very small sample image created in ImageJ):

import numpy as np
import tifffile

infile32 = "test.tif"

with tifffile.TiffFile(infile32) as tif:
    imagej_metadata = tif.imagej_metadata

a = tifffile.imread(infile32)
print(a.shape)

a = np.round(255 * a)
a = a.astype(np.uint8)

tifffile.imwrite("test_py-8bit.tif", a, imagej=True, metadata = imagej_metadata)
>>> (4, 3, 10, 11)

However, the pixel resolution (how many micrometers are in 1 pixel) is wrong, the "z" axis (a.shape[1]) is wrongly recognized as color channel, and the "time" axis (a.shape[0]) is wrongly recognized as z.

If I do this process manually in ImageJ, this problem does not occur, so I suspect the TIFF tags are necessary. I'd like a programmatic way to do it, so I can run the script on a cluster over hundreds of files.

Looking at the documentation of tifffile, I know it's possible to also extract tags:

with tifffile.TiffFile(infile32) as tif:
    for page in tif.pages:
        for tag in page.tags:
            tag_name, tag_value = tag.name, tag.value

But how can I pass these tags to tifffile.imwrite?


Solution

  • Copy the resolution and resolutionunit properties and add the axes order of the image array to the imagej_metadata dict:

    import numpy
    import tifffile
    
    with tifffile.TiffFile('imagej_float32.tif') as tif:
        data = tif.asarray()
        imagej_metadata = tif.imagej_metadata
        imagej_metadata['axes'] = tif.series[0].axes
        resolution = tif.pages[0].resolution
        resolutionunit = tif.pages[0].resolutionunit
    
    del imagej_metadata['hyperstack']
    imagej_metadata['min'] = 0
    imagej_metadata['max'] = 255
    
    tifffile.imwrite(
        'imagej_uint8.tif',
        numpy.round(255 * data).astype(numpy.uint8),
        imagej=True,
        resolution=resolution,
        resolutionunit=resolutionunit,
        metadata=imagej_metadata,
    )