TIFF File Management and OME Files
Authors
Setup
Import Libraries
import numpy as np
import matplotlib.pyplot as plt
from tifffile import TiffFile, imread, imwrite
import json
from pprint import pprint
import xml.dom.minidomDownload Data
Run the below cells to download datasets for the first two sections of the notebook
This might take a while. In the meantime, feel free to read a bit about the datasets. We won’t do any analysis here.
data_endoscope.tif1-photon microendoscopic data from mouse dorsal striatum Reference.Sue_2x_3000_40_-46.tif(taken from CaImAn) dataset by Sue Koay and David Tank. 2-photon data from supragranular parietal cortex mouse during a virtual reality task.
TIFF files are widely used in scientific imaging due to their ability to store multiple image frames and rich metadata in a single container. In this notebook we explore how to read, inspect, and write TIFF files using Python. We begin by reading multi-page TIFF files using both imread and TiffFile, and measure performance when accessing subsets of frames. We then examine embedded metadata, learn how to extract specific fields, and compare metadata across frames. Finally, we write custom TIFF files and embed structured metadata in JSON format. This notebook builds foundational skills for working with microscopy data, especially in experiments that involve large image stacks or OME-TIFF standards.
Section 1: Reading TIFF File
TIFF, which stands for Tagged Image File Format, is a flexible and adaptable file format for storing images and data within a single file. It can be used to store multiple frames as pages.
| Code | Description |
|---|---|
imread |
Reads TIFF files as NumPy arrays, suitable for straightforward image data. |
TiffFile |
Provides more detailed control over reading TIFF files, including accessing metadata and handling complex file structures. |
%%timeit |
Measures the execution time of code blocks, useful for performance optimization. |
matplotlib for plotting |
Enables visualization of image data directly from the TIFF files, essential for data exploration and analysis. |
Exercises
Example: Read data_endoscope.tif. How many frames does it have?
frames = imread('data/data_endoscope.tif')
frames.shape(1000, 128, 128)Exercise: Read Sue_2x_3000_40_-46.tif. How many frames does this data have?
Solution
frames = imread('data/Sue_2x_3000_40_-46.tif')
frames.shape(3000, 170, 170)Exercise: Read Sue_2x_3000_40_-46.tif. How long does it take?
Hint: Put %%timeit in the beginning of the cell
Solution
%%timeit
frames = imread('data/Sue_2x_3000_40_-46.tif')156 ms ± 6.27 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)Exercise: Read Sue_2x_3000_40_-46.tif. How long does it take to access the last frame?
Hint: Put %%timeit in the beginning of the cell
Solution
%%timeit
frames = imread('data/Sue_2x_3000_40_-46.tif')
frames[-1]155 ms ± 3.65 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)Example: Let’s see the plots. Plot the first frame
plt.imshow(frames[0], cmap='gray')Exercise: Plot the last frame
Solution
plt.imshow(frames[-1], cmap='gray')Example: Read only the first 3 frames from Sue_2x_3000_40_-46.tif
frames = imread('data/Sue_2x_3000_40_-46.tif', key=(0, 1, 2))
frames.shape(3, 170, 170)Exercise: Read only 1, 3, 5, 7, 9th frame from Sue_2x_3000_40_-46.tif
Solution
frames = imread('data/Sue_2x_3000_40_-46.tif', key=(0, 2, 4, 6, 8))
frames.shape(5, 170, 170)Exercise: Read only first 100 frames from Sue_2x_3000_40_-46.tif
Hint: use range(0, 100)
Solution
frames = imread('data/Sue_2x_3000_40_-46.tif', key=range(0, 100))
frames.shape(100, 170, 170)Example: Read data_endoscope.tif with TiffFile?
f = TiffFile('data/data_endoscope.tif')
frames = np.array([page.asarray() for page in f.pages])Exercise: Read Sue_2x_3000_40_-46.tif with TiffFile
Solution
f = TiffFile('data/Sue_2x_3000_40_-46.tif')
frames = np.array([page.asarray() for page in f.pages])Exercise: How long does it take to read Sue_2x_3000_40_-46.tif with TiffFile?
Solution
%%timeit
f = TiffFile('data/Sue_2x_3000_40_-46.tif')
frames = np.array([page.asarray() for page in f.pages])1.04 s ± 164 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)Exercise: How long does it take to access only the last frame with TiffFile?
Solution
%%timeit
f = TiffFile("data/data_endoscope.tif")
f.pages[-1].asarray()6.66 ms ± 65.8 μs per loop (mean ± std. dev. of 7 runs, 100 loops each)Section 2: Metadata handling and TIFF file writing
This section focuses on metadata handling and writing TIFF files with custom metadata, for managing and documenting image datasets in research. The methods demonstrated include extracting metadata from TIFF files, writing TIFF files with specified photometric interpretations, and embedding custom JSON-formatted metadata into TIFF files.
| Code | Description |
|---|---|
TiffFile() |
Opens a TIFF file for reading, providing access to image data and metadata. |
.pages[N].tags |
Accesses the tags (metadata) of the Nth page in the TIFF file. |
imwrite() |
Writes image data to a TIFF file, with options for specifying photometric interpretation and embedding custom metadata. |
json.dumps() |
Converts a Python dictionary into a JSON-formatted string suitable for embedding as metadata. |
Exercises
Example: Read and print basic information about data_endoscope.tif
f = TiffFile('data/data_endoscope.tif')
print(f)TiffFile 'data_endoscope.tif' 31.68 MiB 1000 Pages uniformExercise: Read and print basic information about Sue_2x_3000_40_-46.tif
Solution
f = TiffFile('data/Sue_2x_3000_40_-46.tif')
print(f)TiffFile 'Sue_2x_3000_40_-46.tif' 331.13 MiB 3000 Pages shaped|uniformExample: Print detailed information of first page of data_endoscope.tif
f = TiffFile('data/data_endoscope.tif')
print(f.pages[0].tags)TiffTag 256 ImageWidth @33024 SHORT @33032 = 128
TiffTag 257 ImageLength @33036 SHORT @33044 = 128
TiffTag 258 BitsPerSample @33048 SHORT @33056 = 16
TiffTag 259 Compression @33060 SHORT @33068 = PACKBITS
TiffTag 262 PhotometricInterpretation @33072 SHORT @33080 = MINISBLACK
TiffTag 273 StripOffsets @33084 LONG[2] @33220 = (8, 16509)
TiffTag 274 Orientation @33096 SHORT @33104 = TOPLEFT
TiffTag 277 SamplesPerPixel @33108 SHORT @33116 = 1
TiffTag 278 RowsPerStrip @33120 SHORT @33128 = 64
TiffTag 279 StripByteCounts @33132 LONG[2] @33212 = (16501, 16512)
TiffTag 282 XResolution @33144 RATIONAL @33196 = (72, 1)
TiffTag 283 YResolution @33156 RATIONAL @33204 = (72, 1)
TiffTag 284 PlanarConfiguration @33168 SHORT @33176 = CONTIG
TiffTag 296 ResolutionUnit @33180 SHORT @33188 = INCHExercise: Print detailed information of 500th page of data_endoscope.tif. How is it same or different from that of the first page?
Solution
f = TiffFile('data/data_endoscope.tif')
print(f.pages[499].tags)TiffTag 256 ImageWidth @16609952 SHORT @16609960 = 128
TiffTag 257 ImageLength @16609964 SHORT @16609972 = 128
TiffTag 258 BitsPerSample @16609976 SHORT @16609984 = 16
TiffTag 259 Compression @16609988 SHORT @16609996 = PACKBITS
TiffTag 262 PhotometricInterpretation @16610000 SHORT @16610008 = MINISBLACK
TiffTag 273 StripOffsets @16610012 LONG[2] @16610148 = (16576940, 16593437)
TiffTag 274 Orientation @16610024 SHORT @16610032 = TOPLEFT
TiffTag 277 SamplesPerPixel @16610036 SHORT @16610044 = 1
TiffTag 278 RowsPerStrip @16610048 SHORT @16610056 = 64
TiffTag 279 StripByteCounts @16610060 LONG[2] @16610140 = (16497, 16512)
TiffTag 282 XResolution @16610072 RATIONAL @16610124 = (72, 1)
TiffTag 283 YResolution @16610084 RATIONAL @16610132 = (72, 1)
TiffTag 284 PlanarConfiguration @16610096 SHORT @16610104 = CONTIG
TiffTag 296 ResolutionUnit @16610108 SHORT @16610116 = INCHExercise: Print detailed information of 1000th page of data_endoscope.tif. How is it same or different from that of the other two pages?
Solution
f = TiffFile('data/data_endoscope.tif')
print(f.pages[999].tags)TiffTag 256 ImageWidth @33220494 SHORT @33220502 = 128
TiffTag 257 ImageLength @33220506 SHORT @33220514 = 128
TiffTag 258 BitsPerSample @33220518 SHORT @33220526 = 16
TiffTag 259 Compression @33220530 SHORT @33220538 = PACKBITS
TiffTag 262 PhotometricInterpretation @33220542 SHORT @33220550 = MINISBLACK
TiffTag 273 StripOffsets @33220554 LONG[2] @33220690 = (33187470, 33203979)
TiffTag 274 Orientation @33220566 SHORT @33220574 = TOPLEFT
TiffTag 277 SamplesPerPixel @33220578 SHORT @33220586 = 1
TiffTag 278 RowsPerStrip @33220590 SHORT @33220598 = 64
TiffTag 279 StripByteCounts @33220602 LONG[2] @33220682 = (16509, 16512)
TiffTag 282 XResolution @33220614 RATIONAL @33220666 = (72, 1)
TiffTag 283 YResolution @33220626 RATIONAL @33220674 = (72, 1)
TiffTag 284 PlanarConfiguration @33220638 SHORT @33220646 = CONTIG
TiffTag 296 ResolutionUnit @33220650 SHORT @33220658 = INCHExample: Extract the value of ‘ImageWidth’ on 1000th page of data_endoscope
f = TiffFile('data/data_endoscope.tif')
print(f.pages[999].tags['ImageWidth'].value)128Exercise: Extract the value of ‘PhotometricInterpretation’ on 1000th page of data_endoscope
Solution
f = TiffFile('data/data_endoscope.tif')
print(f.pages[999].tags['PhotometricInterpretation'].value)1Exercise: Extract the value of ‘ResolutionUnit’ on 1000th page of data_endoscope
Solution
f = TiffFile('data/data_endoscope.tif')
print(f.pages[999].tags['ResolutionUnit'].value)2