Writing ImageJ compatible metadata

Source code notebook Author

ImageJ is a commonly used image processing software for working with TIFFs. You might want to add X and Y resolution information to your TiffImages.jl TIFFs that works with ImageJ.

First, we need to assign the resolution unit by adding a RESOLUTIONUNIT tag to each IFD in the image

using Images, TiffImages, Unitful
img0 = zeros(Gray{N0f8}, 10, 10, 12) #example image
img = TiffImages.DenseTaggedImage(img0)


resunit = UInt8(3) # 1: No absolute unit of measurement, 2: Inch, 3: Centimeter
[ifd[TiffImages.RESOLUTIONUNIT] = resunit for ifd in ifds(img)];

Then, we can add the XRESOLUTION and YRESOLUTION TIFF tags to store the number of pixels per RESOLUTIONUNIT.

resxy = Rational{UInt32}(round(1u"cm"/0.653u"μm", digits = 3)) # Type must be rational. In this example, the pixel size is 0.653 μm x 0.653 μm.
[ifd[TiffImages.XRESOLUTION] = resxy for ifd in ifds(img)]
[ifd[TiffImages.YRESOLUTION] = resxy for ifd in ifds(img)]
first(ifds(img))
IFD, with tags: 
	Tag(IMAGEWIDTH, 10)
	Tag(IMAGELENGTH, 10)
	Tag(BITSPERSAMPLE, 8)
	Tag(PHOTOMETRIC, 1)
	Tag(SAMPLESPERPIXEL, 1)
	Tag(XRESOLUTION, 0x001d3582//0x0000007d)
	Tag(YRESOLUTION, 0x001d3582//0x0000007d)
	Tag(RESOLUTIONUNIT, 3)
	Tag(SAMPLEFORMAT, 1)

Now if we want to add Z and time information to a TIFF, it's a bit more complicated because the TIFF spec doesn't have a standard way of representing this information. ImageJ has a poorly documented way to add this information by writing to an IMAGEDESCRIPTION tag in the first IFD.

The following tells ImageJ that it is a hyperstack with 3 timepoints and 4 Z slices with a 0.2 interval (in secs) between frames and a 5 micron spacing, respectively.

first(ifds(img))[TiffImages.IMAGEDESCRIPTION] = # only in the first IFD
"ImageJ=1.51d
images=12
frames=3
slices=4
hyperstack=true
spacing=5.0
unit=um
finterval=0.2
axes=TZYX"

first(ifds(img))
IFD, with tags: 
	Tag(IMAGEWIDTH, 10)
	Tag(IMAGELENGTH, 10)
	Tag(BITSPERSAMPLE, 8)
	Tag(PHOTOMETRIC, 1)
	Tag(IMAGEDESCRIPTION, "ImageJ=1.51d
images=...")
	Tag(SAMPLESPERPIXEL, 1)
	Tag(XRESOLUTION, 0x001d3582//0x0000007d)
	Tag(YRESOLUTION, 0x001d3582//0x0000007d)
	Tag(RESOLUTIONUNIT, 3)
	Tag(SAMPLEFORMAT, 1)

Then write the image to disk

TiffImages.save("imagej.tiff", img)

Opening the file in ImageJ shows that it's recognized as a hyperstack with the proper XYZT information:


This page was generated using DemoCards.jl and Literate.jl.