toto
toto

Reputation: 360

Adding custom extratags with tifffile

I'm trying to write a script to simplify my everyday life in the lab. I operate one ThermoFisher / FEI scanning electron microscope and I save all my pictures in the TIFF format.

The microscope software is adding an extensive custom TiffTag (code 34682) containing all the microscope / image parameters.

In my script, I would like to open an image, perform some manipulations and then save the data in a new file, including the original FEI metadata. To do so, I would like to use a python script using the tifffile module.

I can open the image file and perform the needed manipulations without problems. Retrieving the FEI metadata from the input file is also working fine.

I was thinking to use the imwrite function to save the output file and using the extratags optional argument to transfer to the output file the original FEI metadata.

This is an extract of the tifffile documentation about the extratags:

   extratags : sequence of tuples
       Additional tags as [(code, dtype, count, value, writeonce)].
       code : int
           The TIFF tag Id.
       dtype : int or str
           Data type of items in 'value'. One of TIFF.DATATYPES.
       count : int
           Number of data values. Not used for string or bytes values.
       value : sequence
           'Count' values compatible with 'dtype'.
           Bytes must contain count values of dtype packed as binary data.
       writeonce : bool
           If True, the tag is written to the first page of a series only.

Here is a snippet of my code.

my_extratags = [(input_tags['FEI_HELIOS'].code,
 input_tags['FEI_HELIOS'].dtype, 
 input_tags['FEI_HELIOS'].count,
 input_tags['FEI_HELIOS'].value, True)]

tifffile.imwrite('output.tif', data, extratags = my_extratags)

This code is not working and complaining that the value of the extra tag should be ASCII 7-bit encoded. This looks already very strange to me because I haven't touched the metadata and I am just copying it to the output file.

If I convert the metadata tag value in a string as below:

my_extratags = [(input_tags['FEI_HELIOS'].code,
 input_tags['FEI_HELIOS'].dtype, 
 input_tags['FEI_HELIOS'].count,
 str(input_tags['FEI_HELIOS'].value), True)]

tifffile.imwrite('output.tif', data, extratags = my_extratags)

the code is working, the image is saved, the metadata corresponding to 'FEI_HELIOS' is created but it is empty!

Can you help me in finding what I am doing wrongly? I don't need to use tifffile, but I would prefer to use python rather than ImageJ because I have already several other python scripts and I would like to integrate this new one with the others.

Thanks a lot in advance!

toto

ps. I'm a frequent user of stackoverflow, but this is actually my first question!

Upvotes: 0

Views: 1590

Answers (1)

cgohlke
cgohlke

Reputation: 9437

In principle the approach is correct. However, tifffile parses the raw values of certain tags, including FEI_HELIOS, to dictionaries or other Python types. To get the raw tag value for rewriting, it needs to be read from file again. In these cases, use the internal TiffTag._astuple function to get an extratag compatible tuple of the tag, e.g.:

import tifffile

with tifffile.TiffFile('FEI_SEM.tif') as tif:
    assert tif.is_fei
    page = tif.pages[0]
    image = page.asarray()
    ...  # process image
    with tifffile.TiffWriter('copy1.tif') as out:
        out.write(
            image,
            photometric=page.photometric,
            compression=page.compression,
            planarconfig=page.planarconfig,
            rowsperstrip=page.rowsperstrip,
            resolution=(
                page.tags['XResolution'].value,
                page.tags['YResolution'].value,
                page.tags['ResolutionUnit'].value,
            ),
            extratags=[page.tags['FEI_HELIOS']._astuple()],
        )

This approach does not preserve Exif metadata, which tifffile cannot write.

Another approach, since FEI files seem to be written uncompressed, is to directly memory map the image data in the file to a numpy array and manipulate that array:

import shutil
import tifffile

shutil.copyfile('FEI_SEM.tif', 'copy2.tif')

image = tifffile.memmap('copy2.tif')
...  # process image
image.flush()

Finally, consider tifftools for rewriting TIFF files where tifffile is currently failing, e.g. Exif metadata.

Upvotes: 2

Related Questions