Keep image description metadata in a Stack after modifying it

Hello,
I am writing a stack file from several images in python using the tifffile package.
Then I modify it in Fiji (I do a manual segmentation) and I want to save it to be readable in python again.
Every image in the stack has as description the single image filename.
When I modify the Stack and save it as “Stack_segmented” the information is gone or not accessible.

What I would like is to get the single images after the manual segmentation in a new folder, each with their description as filename (the description contains their original filename).

This is how I write the Stack from single images:

import tifffile as tiff

with tiff.TiffWriter(output_filename, bigtiff=True) as tif_writer:
    for filename in natsorted(os.listdir(path)):
        img=tiff.imread(os.path.join(path,filename),name=filename)
        tif_writer.save(img, photometric='minisblack', description=filename, metadata=None)

This is how I create the single images from a stack:

with tiff.TiffFile(input_filename, multifile=True) as tif:
    for page in tif.pages:
        img=page.asarray()
        description=page.description
        tiff.imsave(file=os.path.join(output_path,description), data=img, photometric='minisblack')

The code above works when I don’t modify the Stack on Fiji. But when I modify it then the description is overwritten and page.description contains:
ImageJ=
hyperstack=true
images=1453
channels=1
slices=1
frames=1453
for all images in the stack so I only create one file with the name “IMAGEJ~1.53C” which is overwritten in every iteration.

How could I keep the description data of each file after modifying the Stack?
I have tried it “Save as tif” as well as exporting with Bio-Formats but I have the same problem.

Thank you very much for your help.

There are a number of possible solutions, if you are using a script or macro to modify the files in FIJI then it might be easiest to use imp.setProperty(key, value) in a scripting language or
setMetadata(“Info”, YourLongMetadataString) in the macro.

Alternatively if the original file is in OME-TIFF format before modifying it then any key value pairs in the image description will be preserved in the global metadata when exported as OME-TIFF again.

Hi David,
Thank you for your quick response.
I guess the problem is that I don’t know how to access the value I set as description in the python code once I am in Fiji.

If I do:
print(getInfo(“image.description”));

I get this:

<?xml version="1.0" encoding="UTF-8"?> < OME xmlns="http://www.openmicroscopy.org/Schemas/OME/2016-06" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.openmicroscopy.org/Schemas/OME/2016-06 http://www.openmicroscopy.org/Schemas/OME/2016-06/ome.xsd">img003551.tiff < /Description>< Pixels BigEndian="false" DimensionOrder="XYCZT" ID="Pixels:0" Interleaved="false" PhysicalSizeX="1.0" PhysicalSizeXUnit="µm" PhysicalSizeY="1.0" PhysicalSizeYUnit="µm" SignificantBits="8" SizeC="1" SizeT="1453" SizeX="608" SizeY="610" SizeZ="1" Type="uint8">< Channel ID="Channel:0:0" SamplesPerPixel="1" >< LightPath/>< /Channel>< /Pixels>< /OME>

The < Description> contains img003551.tiff for all the frames of the stack (only first image should have this description).

How could I change the tiff writer to save it in ome tiff format?

I have tried setting ome=True

import tifffile as tiff

with tiff.TiffWriter(output_filename, bigtiff=True, ome=True) as tif_writer:
    for filename in natsorted(os.listdir(path)):
        img=tiff.imread(os.path.join(path,filename),name=filename)
        tif_writer.save(img, photometric='minisblack', description=filename, metadata=None)

But then iI get this warning:
/users/ulises.rey/anaconda3/envs/openCV/lib/python3.7/site-packages/tifffile/tifffile.py:1514: UserWarning: TiffWriter: not writing description to OME-TIFF
UserWarning,

if I do save as a metadata instead of description:

import tifffile as tiff

with tiff.TiffWriter(output_filename, bigtiff=True, ome=True) as tif_writer:
    for filename in natsorted(os.listdir(path)):
        img=tiff.imread(os.path.join(path,filename),name=filename)
        tif_writer.save(img, photometric='minisblack', metadata={'filename': filename})

I don’t get the error but it creates a Stack that Fiji reads as Series and where I can’t find the filename either.

Thanks for your help

Try to write an ImageJ hyperstack compatible file and store the file names in the Info field of the IJMetadata tag. ImageJ should preserve that information when re-saving:

import glob
import tifffile

# read the image stack
files = tifffile.natural_sorted(glob.glob('*.tif'))
image = tifffile.imread(files)

# save the image and metadata in ImageJ format
tifffile.imwrite('imagej.tif', image, imagej=True, metadata= {'Info': '\n'.join(files)})

# edit and re-save with ImageJ
...

# read image and metadata
with tifffile.TiffFile('imagej.tif') as tif:
    files = tif.imagej_metadata['Info'].split('\n')
    image = tif.asarray()

for i, fname in enumerate(files):
    tifffile.imsave(fname + '_copy.tif', image[i])
2 Likes

Hi Christoph,
This works for me now. Thank you very much.

I guess originally I wanted to write using a writer object because usually I am working with many files (hundreds of thousands of images). It seems that imagej format needs to know the total number of files before writing metadata. Is this correct?

For this specific task I can load all images in the memory since they are not many, but what I tried was:

with tiff.TiffWriter(output_filename, imagej=True, bigtiff=True) as tif_writer:
    for filename in natsorted(os.listdir(path)):
        img=tiff.imread(os.path.join(path,filename)),name=filename)
        tif_writer.save(img, photometric='minisblack', metadata= {'Info': filename})   

And got the error:
ValueError: ImageJ does not support non-contiguous series

Thank you again!

ImageJ stores all metadata in the first page and the image data are stored contiguously. This might work:

metadata = {'Info': '\n'.join(files)}

with tifffile.TiffWriter('imagej.tif', imagej=True) as tif:
    for filename in files:
        image = tifffile.imread(filename)
        tif.write(
            image, contiguous=True, photometric='minisblack', metadata=metadata
        )
        metadata = None
1 Like

Thanks! This worked!

I just changed the files so that it only contains the basename, then I can write the files in any directory I specify more easily.
It looks like this:

    files = natsorted(os.listdir(path))
    metadata = {'Info': '\n'.join(files)}

    with tiff.TiffWriter(output_filename, imagej=True) as tif:
        for filename in files:
            image = tiff.imread(os.path.join(path,filename))
            tif.write(image, contiguous=True, photometric='minisblack', metadata=metadata)
            metadata = None

To have the part that goes from stack to images without loading the whole stack I wrote this which works fine :slight_smile:

    with tiff.TiffFile(input_filename) as tif:
        files = tif.imagej_metadata['Info'].split('\n')
        for idx,page in enumerate(tif.pages):
            img=page.asarray()
            filename=files[idx]
            tiff.imsave(os.path.join(output_path, filename), img)

Thanks again!