ijtiff

Rory Nolan

2017-12-19

Reading ImageJ TIFF files

path_2ch_ij <- system.file("img", "2ch_ij.tif", package = "ijtiff")

path_2ch_ij is the path to a 2-channel, five-frame image which was saved from ImageJ.

The original tiff library

When we import it with the original tiff library:

img <- tiff::readTIFF(path_2ch_ij, all = TRUE)
#> Warning in tiff::readTIFF(path_2ch_ij, all = TRUE): TIFFReadDirectory:
#> Unknown field with tag 50838 (0xc696) encountered
#> Warning in tiff::readTIFF(path_2ch_ij, all = TRUE): TIFFReadDirectory:
#> Unknown field with tag 50839 (0xc697) encountered
str(img)  # 10 images
#> List of 10
#>  $ : num [1:128, 1:128] 0 0 0 0.00392 0 ...
#>  $ : num [1:128, 1:128] 0 0.00392 0.00392 0.00392 0 ...
#>  $ : num [1:128, 1:128] 0.00392 0.00392 0 0 0 ...
#>  $ : num [1:128, 1:128] 0 0 0 0.00392 0 ...
#>  $ : num [1:128, 1:128] 0 0 0.00392 0 0 ...
#>  $ : num [1:128, 1:128] 0 0 0.00392 0 0 ...
#>  $ : num [1:128, 1:128] 0 0.00392 0 0 0 ...
#>  $ : num [1:128, 1:128] 0 0 0 0.00392 0.00392 ...
#>  $ : num [1:128, 1:128] 0 0 0 0 0 ...
#>  $ : num [1:128, 1:128] 0 0 0 0.00392 0 ...
img[[1]][100:110, 101:105]  # print a section of the first image in the series
#>             [,1]       [,2]        [,3]        [,4]        [,5]
#>  [1,] 0.01176471 0.01176471 0.035294118 0.027450980 0.023529412
#>  [2,] 0.02352941 0.02745098 0.015686275 0.027450980 0.035294118
#>  [3,] 0.05490196 0.02352941 0.031372549 0.031372549 0.035294118
#>  [4,] 0.03921569 0.01568627 0.027450980 0.023529412 0.027450980
#>  [5,] 0.04313725 0.04313725 0.031372549 0.015686275 0.015686275
#>  [6,] 0.02352941 0.02352941 0.039215686 0.011764706 0.007843137
#>  [7,] 0.03137255 0.03529412 0.027450980 0.023529412 0.019607843
#>  [8,] 0.01960784 0.03921569 0.019607843 0.015686275 0.031372549
#>  [9,] 0.01568627 0.01960784 0.015686275 0.007843137 0.019607843
#> [10,] 0.05490196 0.04705882 0.019607843 0.035294118 0.023529412
#> [11,] 0.03137255 0.02352941 0.007843137 0.023529412 0.027450980

The ijtiff library

When we import the same image with the ijtiff library:

img <- ijtiff::read_tif(path_2ch_ij)
#> Reading a 128x128 pixel image of unsigned integer type with 2 channels and 5 frames.
dim(img)  # 2 channels, 5 frames
#> [1] 128 128   2   5
img[100:110, 101:105, 1, 1]  # print a section of the first channel, first frame
#>       [,1] [,2] [,3] [,4] [,5]
#>  [1,]    3    3    9    7    6
#>  [2,]    6    7    4    7    9
#>  [3,]   14    6    8    8    9
#>  [4,]   10    4    7    6    7
#>  [5,]   11   11    8    4    4
#>  [6,]    6    6   10    3    2
#>  [7,]    8    9    7    6    5
#>  [8,]    5   10    5    4    8
#>  [9,]    4    5    4    2    5
#> [10,]   14   12    5    9    6
#> [11,]    8    6    2    6    7

ijtiff also includes a basic image display function:

ijtiff::display(img[, , 1, 1])  # first channel, first frame

Note

The original tiff package reads several types of TIFFs correctly, including many that are saved from ImageJ. This is just an example of a TIFF type that it doesn’t perform so well with.

Floating point TIFFs

The original tiff package could read but not write floating point (real-numbered) TIFF files. The ijtiff library can do both. It automatically decides which type is appropriate when writing.

Advice for all ImageJ users

Base ImageJ (similar to the tiff R package) does not properly open some perfectly TIFF files1 (including some TIFF files written by the tiff and ijtiff R packages). Instead it gives you the error message: imagej can only open 8 and 16 bit/channel images. These images in fact can be opened in ImageJ using the wonderful BioFormats plugin. See https://imagej.net/Bio-Formats.

No support for volumetric, time based images

The package supports volumetric (\(z\)-stack) and time-based (time-stack) images, but not both volume and time simultaneously. The fourth slot in an ijtiff_img is either for \(z\) or time.

Text Images

TIFF files are limited in which numbers they can represent (they can’t go outside the 32-bit range). Real-numbered TIFFs can also lack precision, having only the precision of a 32-bit floating point number. If TIFF isn’t good enough, you can use text images.

library(ijtiff)
img[1] <- 2 ^ 99  # too high for TIFF
write_tif(img, "img")  # errors
#> Error in write_tif(img, "img"): The maximum value in 'img' is greater than 2 ^ 32 - 1 and therefore too high to be written to a TIFF file.
write_txt_img(img, "img")  # no problem

  1. I think native ImageJ only likes 1, 3 and 4-channel images and complains about the rest, but I’m not sure about this.