From 579882e284527c6a3fddccfceeaa546cad08617c Mon Sep 17 00:00:00 2001 From: Christoph Gohlke Date: Thu, 23 May 2024 06:20:27 +0000 Subject: [PATCH] Release v2024.5.22 --- README.rst | 721 ++++++++++++++++++++++++++++------------------------- 1 file changed, 378 insertions(+), 343 deletions(-) diff --git a/README.rst b/README.rst index 0adb049..8216e20 100644 --- a/README.rst +++ b/README.rst @@ -1,3 +1,6 @@ +.. + This file is generated by setup.py + Read and write TIFF files ========================= @@ -30,7 +33,7 @@ many proprietary metadata formats. :Author: `Christoph Gohlke `_ :License: BSD 3-Clause -:Version: 2024.5.10 +:Version: 2024.5.22 :DOI: `10.5281/zenodo.6795860 `_ Quickstart @@ -72,19 +75,31 @@ This revision was tested with the following requirements and dependencies (required for encoding or decoding LZW, JPEG, etc. compressed segments) - `Matplotlib `_ 3.8.4 (required for plotting) -- `Lxml `_ 5.2.1 +- `Lxml `_ 5.2.2 (required only for validating and printing XML) -- `Zarr `_ 2.18.0 +- `Zarr `_ 2.18.1 (required only for opening Zarr stores) -- `Fsspec `_ 2024.3.1 +- `Fsspec `_ 2024.5.0 (required only for opening ReferenceFileSystem files) Revisions --------- +2024.5.22 + +- Pass 5084 tests. +- Derive TiffPages, TiffPageSeries, FileSequence, StoredShape from Sequence. +- Truncate circular IFD chain, do not raise TiffFileError (breaking). +- Deprecate access to TiffPages.pages and FileSequence.files. +- Enable DeprecationWarning for enums in TIFF namespace. +- Remove some deprecated code (breaking). +- Add iccprofile property to TiffPage and parameter to TiffWriter.write. +- Do not detect VSI as SIS format. +- Limit length of logged exception messages. +- Work around GitHub not rendering docstring examples (#254, #255). + 2024.5.10 -- Pass 5082 tests. - Support reading JPEGXL compression in DNG 1.7. - Read invalid TIFF created by IDEAS software. @@ -182,57 +197,6 @@ Revisions 2023.3.21 -- Fix reading MMstack with missing data (#187). - -2023.3.15 - -- Fix corruption using tile generators with prediction/compression (#185). -- Add parser for Micro-Manager MMStack series (breaking). -- Return micromanager_metadata IndexMap as numpy array (breaking). -- Revert optimizations for Micro-Manager OME series. -- Do not use numcodecs zstd in write_fsspec (kerchunk issue 317). -- More type annotations. - -2023.2.28 - -- Fix reading some Micro-Manager metadata from corrupted files. -- Speed up reading Micro-Manager indexmap for creation of OME series. - -2023.2.27 - -- Use Micro-Manager indexmap offsets to create virtual TiffFrames. -- Fixes for future imagecodecs. - -2023.2.3 - -- Fix overflow in calculation of databytecounts for large NDPI files. - -2023.2.2 - -- Fix regression reading layered NDPI files. -- Add option to specify offset in FileHandle.read_array. - -2023.1.23 - -- Support reading NDTiffStorage. -- Support reading PIXTIFF compression. -- Support LERC with Zstd or Deflate compression. -- Do not write duplicate and select extratags. -- Allow to write uncompressed image data beyond 4 GB in classic TIFF. -- Add option to specify chunkshape and dtype in FileSequence.asarray. -- Add option for imread to write to output in FileSequence.asarray (#172). -- Add function to read GDAL structural metadata. -- Add function to read NDTiff.index files. -- Fix IndexError accessing TiffFile.mdgel_metadata in non-MDGEL files. -- Fix unclosed file ResourceWarning in TiffWriter. -- Fix non-bool predictor arguments (#167). -- Relax detection of OME-XML (#173). -- Rename some TiffFrame parameters (breaking). -- Deprecate squeeze_axes (will change signature). -- Use defusexml in xml2dict. - -2022.10.10 - - … Refer to the CHANGES file for older revisions. @@ -405,411 +369,482 @@ Examples Write a NumPy array to a single-page RGB TIFF file: ->>> data = numpy.random.randint(0, 255, (256, 256, 3), 'uint8') ->>> imwrite('temp.tif', data, photometric='rgb') +.. code-block:: python + + >>> data = numpy.random.randint(0, 255, (256, 256, 3), 'uint8') + >>> imwrite('temp.tif', data, photometric='rgb') Read the image from the TIFF file as NumPy array: ->>> image = imread('temp.tif') ->>> image.shape -(256, 256, 3) +.. code-block:: python + + >>> image = imread('temp.tif') + >>> image.shape + (256, 256, 3) Use the `photometric` and `planarconfig` arguments to write a 3x3x3 NumPy array to an interleaved RGB, a planar RGB, or a 3-page grayscale TIFF: ->>> data = numpy.random.randint(0, 255, (3, 3, 3), 'uint8') ->>> imwrite('temp.tif', data, photometric='rgb') ->>> imwrite('temp.tif', data, photometric='rgb', planarconfig='separate') ->>> imwrite('temp.tif', data, photometric='minisblack') +.. code-block:: python + + >>> data = numpy.random.randint(0, 255, (3, 3, 3), 'uint8') + >>> imwrite('temp.tif', data, photometric='rgb') + >>> imwrite('temp.tif', data, photometric='rgb', planarconfig='separate') + >>> imwrite('temp.tif', data, photometric='minisblack') Use the `extrasamples` argument to specify how extra components are interpreted, for example, for an RGBA image with unassociated alpha channel: ->>> data = numpy.random.randint(0, 255, (256, 256, 4), 'uint8') ->>> imwrite('temp.tif', data, photometric='rgb', extrasamples=['unassalpha']) +.. code-block:: python + + >>> data = numpy.random.randint(0, 255, (256, 256, 4), 'uint8') + >>> imwrite('temp.tif', data, photometric='rgb', extrasamples=['unassalpha']) Write a 3-dimensional NumPy array to a multi-page, 16-bit grayscale TIFF file: ->>> data = numpy.random.randint(0, 2**12, (64, 301, 219), 'uint16') ->>> imwrite('temp.tif', data, photometric='minisblack') +.. code-block:: python + + >>> data = numpy.random.randint(0, 2**12, (64, 301, 219), 'uint16') + >>> imwrite('temp.tif', data, photometric='minisblack') Read the whole image stack from the multi-page TIFF file as NumPy array: ->>> image_stack = imread('temp.tif') ->>> image_stack.shape -(64, 301, 219) ->>> image_stack.dtype -dtype('uint16') +.. code-block:: python + + >>> image_stack = imread('temp.tif') + >>> image_stack.shape + (64, 301, 219) + >>> image_stack.dtype + dtype('uint16') Read the image from the first page in the TIFF file as NumPy array: ->>> image = imread('temp.tif', key=0) ->>> image.shape -(301, 219) +.. code-block:: python + + >>> image = imread('temp.tif', key=0) + >>> image.shape + (301, 219) Read images from a selected range of pages: ->>> images = imread('temp.tif', key=range(4, 40, 2)) ->>> images.shape -(18, 301, 219) +.. code-block:: python + + >>> images = imread('temp.tif', key=range(4, 40, 2)) + >>> images.shape + (18, 301, 219) Iterate over all pages in the TIFF file and successively read images: ->>> with TiffFile('temp.tif') as tif: -... for page in tif.pages: -... image = page.asarray() -... +.. code-block:: python + + >>> with TiffFile('temp.tif') as tif: + ... for page in tif.pages: + ... image = page.asarray() + ... Get information about the image stack in the TIFF file without reading any image data: ->>> tif = TiffFile('temp.tif') ->>> len(tif.pages) # number of pages in the file -64 ->>> page = tif.pages[0] # get shape and dtype of image in first page ->>> page.shape -(301, 219) ->>> page.dtype -dtype('uint16') ->>> page.axes -'YX' ->>> series = tif.series[0] # get shape and dtype of first image series ->>> series.shape -(64, 301, 219) ->>> series.dtype -dtype('uint16') ->>> series.axes -'QYX' ->>> tif.close() +.. code-block:: python + + >>> tif = TiffFile('temp.tif') + >>> len(tif.pages) # number of pages in the file + 64 + >>> page = tif.pages[0] # get shape and dtype of image in first page + >>> page.shape + (301, 219) + >>> page.dtype + dtype('uint16') + >>> page.axes + 'YX' + >>> series = tif.series[0] # get shape and dtype of first image series + >>> series.shape + (64, 301, 219) + >>> series.dtype + dtype('uint16') + >>> series.axes + 'QYX' + >>> tif.close() Inspect the "XResolution" tag from the first page in the TIFF file: ->>> with TiffFile('temp.tif') as tif: -... tag = tif.pages[0].tags['XResolution'] -... ->>> tag.value -(1, 1) ->>> tag.name -'XResolution' ->>> tag.code -282 ->>> tag.count -1 ->>> tag.dtype - +.. code-block:: python + + >>> with TiffFile('temp.tif') as tif: + ... tag = tif.pages[0].tags['XResolution'] + ... + >>> tag.value + (1, 1) + >>> tag.name + 'XResolution' + >>> tag.code + 282 + >>> tag.count + 1 + >>> tag.dtype + Iterate over all tags in the TIFF file: ->>> with TiffFile('temp.tif') as tif: -... for page in tif.pages: -... for tag in page.tags: -... tag_name, tag_value = tag.name, tag.value -... +.. code-block:: python + + >>> with TiffFile('temp.tif') as tif: + ... for page in tif.pages: + ... for tag in page.tags: + ... tag_name, tag_value = tag.name, tag.value + ... Overwrite the value of an existing tag, for example, XResolution: ->>> with TiffFile('temp.tif', mode='r+') as tif: -... _ = tif.pages[0].tags['XResolution'].overwrite((96000, 1000)) -... +.. code-block:: python + + >>> with TiffFile('temp.tif', mode='r+') as tif: + ... _ = tif.pages[0].tags['XResolution'].overwrite((96000, 1000)) + ... Write a 5-dimensional floating-point array using BigTIFF format, separate color components, tiling, Zlib compression level 8, horizontal differencing predictor, and additional metadata: ->>> data = numpy.random.rand(2, 5, 3, 301, 219).astype('float32') ->>> imwrite( -... 'temp.tif', -... data, -... bigtiff=True, -... photometric='rgb', -... planarconfig='separate', -... tile=(32, 32), -... compression='zlib', -... compressionargs={'level': 8}, -... predictor=True, -... metadata={'axes': 'TZCYX'}, -... ) +.. code-block:: python + + >>> data = numpy.random.rand(2, 5, 3, 301, 219).astype('float32') + >>> imwrite( + ... 'temp.tif', + ... data, + ... bigtiff=True, + ... photometric='rgb', + ... planarconfig='separate', + ... tile=(32, 32), + ... compression='zlib', + ... compressionargs={'level': 8}, + ... predictor=True, + ... metadata={'axes': 'TZCYX'}, + ... ) Write a 10 fps time series of volumes with xyz voxel size 2.6755x2.6755x3.9474 micron^3 to an ImageJ hyperstack formatted TIFF file: ->>> volume = numpy.random.randn(6, 57, 256, 256).astype('float32') ->>> image_labels = [f'{i}' for i in range(volume.shape[0] * volume.shape[1])] ->>> imwrite( -... 'temp.tif', -... volume, -... imagej=True, -... resolution=(1.0 / 2.6755, 1.0 / 2.6755), -... metadata={ -... 'spacing': 3.947368, -... 'unit': 'um', -... 'finterval': 1 / 10, -... 'fps': 10.0, -... 'axes': 'TZYX', -... 'Labels': image_labels, -... }, -... ) +.. code-block:: python + + >>> volume = numpy.random.randn(6, 57, 256, 256).astype('float32') + >>> image_labels = [f'{i}' for i in range(volume.shape[0] * volume.shape[1])] + >>> imwrite( + ... 'temp.tif', + ... volume, + ... imagej=True, + ... resolution=(1.0 / 2.6755, 1.0 / 2.6755), + ... metadata={ + ... 'spacing': 3.947368, + ... 'unit': 'um', + ... 'finterval': 1 / 10, + ... 'fps': 10.0, + ... 'axes': 'TZYX', + ... 'Labels': image_labels, + ... }, + ... ) Read the volume and metadata from the ImageJ hyperstack file: ->>> with TiffFile('temp.tif') as tif: -... volume = tif.asarray() -... axes = tif.series[0].axes -... imagej_metadata = tif.imagej_metadata -... ->>> volume.shape -(6, 57, 256, 256) ->>> axes -'TZYX' ->>> imagej_metadata['slices'] -57 ->>> imagej_metadata['frames'] -6 +.. code-block:: python + + >>> with TiffFile('temp.tif') as tif: + ... volume = tif.asarray() + ... axes = tif.series[0].axes + ... imagej_metadata = tif.imagej_metadata + ... + >>> volume.shape + (6, 57, 256, 256) + >>> axes + 'TZYX' + >>> imagej_metadata['slices'] + 57 + >>> imagej_metadata['frames'] + 6 Memory-map the contiguous image data in the ImageJ hyperstack file: ->>> memmap_volume = memmap('temp.tif') ->>> memmap_volume.shape -(6, 57, 256, 256) ->>> del memmap_volume +.. code-block:: python + + >>> memmap_volume = memmap('temp.tif') + >>> memmap_volume.shape + (6, 57, 256, 256) + >>> del memmap_volume Create a TIFF file containing an empty image and write to the memory-mapped NumPy array (note: this does not work with compression or tiling): ->>> memmap_image = memmap( -... 'temp.tif', shape=(256, 256, 3), dtype='float32', photometric='rgb' -... ) ->>> type(memmap_image) - ->>> memmap_image[255, 255, 1] = 1.0 ->>> memmap_image.flush() ->>> del memmap_image +.. code-block:: python + + >>> memmap_image = memmap( + ... 'temp.tif', shape=(256, 256, 3), dtype='float32', photometric='rgb' + ... ) + >>> type(memmap_image) + + >>> memmap_image[255, 255, 1] = 1.0 + >>> memmap_image.flush() + >>> del memmap_image Write two NumPy arrays to a multi-series TIFF file (note: other TIFF readers will not recognize the two series; use the OME-TIFF format for better interoperability): ->>> series0 = numpy.random.randint(0, 255, (32, 32, 3), 'uint8') ->>> series1 = numpy.random.randint(0, 255, (4, 256, 256), 'uint16') ->>> with TiffWriter('temp.tif') as tif: -... tif.write(series0, photometric='rgb') -... tif.write(series1, photometric='minisblack') -... +.. code-block:: python + + >>> series0 = numpy.random.randint(0, 255, (32, 32, 3), 'uint8') + >>> series1 = numpy.random.randint(0, 255, (4, 256, 256), 'uint16') + >>> with TiffWriter('temp.tif') as tif: + ... tif.write(series0, photometric='rgb') + ... tif.write(series1, photometric='minisblack') + ... Read the second image series from the TIFF file: ->>> series1 = imread('temp.tif', series=1) ->>> series1.shape -(4, 256, 256) +.. code-block:: python + + >>> series1 = imread('temp.tif', series=1) + >>> series1.shape + (4, 256, 256) Successively write the frames of one contiguous series to a TIFF file: ->>> data = numpy.random.randint(0, 255, (30, 301, 219), 'uint8') ->>> with TiffWriter('temp.tif') as tif: -... for frame in data: -... tif.write(frame, contiguous=True) -... +.. code-block:: python + + >>> data = numpy.random.randint(0, 255, (30, 301, 219), 'uint8') + >>> with TiffWriter('temp.tif') as tif: + ... for frame in data: + ... tif.write(frame, contiguous=True) + ... Append an image series to the existing TIFF file (note: this does not work with ImageJ hyperstack or OME-TIFF files): ->>> data = numpy.random.randint(0, 255, (301, 219, 3), 'uint8') ->>> imwrite('temp.tif', data, photometric='rgb', append=True) +.. code-block:: python + + >>> data = numpy.random.randint(0, 255, (301, 219, 3), 'uint8') + >>> imwrite('temp.tif', data, photometric='rgb', append=True) Create a TIFF file from a generator of tiles: ->>> data = numpy.random.randint(0, 2**12, (31, 33, 3), 'uint16') ->>> def tiles(data, tileshape): -... for y in range(0, data.shape[0], tileshape[0]): -... for x in range(0, data.shape[1], tileshape[1]): -... yield data[y : y + tileshape[0], x : x + tileshape[1]] -... ->>> imwrite( -... 'temp.tif', -... tiles(data, (16, 16)), -... tile=(16, 16), -... shape=data.shape, -... dtype=data.dtype, -... photometric='rgb', -... ) +.. code-block:: python + + >>> data = numpy.random.randint(0, 2**12, (31, 33, 3), 'uint16') + >>> def tiles(data, tileshape): + ... for y in range(0, data.shape[0], tileshape[0]): + ... for x in range(0, data.shape[1], tileshape[1]): + ... yield data[y : y + tileshape[0], x : x + tileshape[1]] + ... + >>> imwrite( + ... 'temp.tif', + ... tiles(data, (16, 16)), + ... tile=(16, 16), + ... shape=data.shape, + ... dtype=data.dtype, + ... photometric='rgb', + ... ) Write a multi-dimensional, multi-resolution (pyramidal), multi-series OME-TIFF file with metadata. Sub-resolution images are written to SubIFDs. Limit parallel encoding to 2 threads. Write a thumbnail image as a separate image series: ->>> data = numpy.random.randint(0, 255, (8, 2, 512, 512, 3), 'uint8') ->>> subresolutions = 2 ->>> pixelsize = 0.29 # micrometer ->>> with TiffWriter('temp.ome.tif', bigtiff=True) as tif: -... metadata = { -... 'axes': 'TCYXS', -... 'SignificantBits': 8, -... 'TimeIncrement': 0.1, -... 'TimeIncrementUnit': 's', -... 'PhysicalSizeX': pixelsize, -... 'PhysicalSizeXUnit': 'µm', -... 'PhysicalSizeY': pixelsize, -... 'PhysicalSizeYUnit': 'µm', -... 'Channel': {'Name': ['Channel 1', 'Channel 2']}, -... 'Plane': {'PositionX': [0.0] * 16, 'PositionXUnit': ['µm'] * 16}, -... } -... options = dict( -... photometric='rgb', -... tile=(128, 128), -... compression='jpeg', -... resolutionunit='CENTIMETER', -... maxworkers=2, -... ) -... tif.write( -... data, -... subifds=subresolutions, -... resolution=(1e4 / pixelsize, 1e4 / pixelsize), -... metadata=metadata, -... **options, -... ) -... # write pyramid levels to the two subifds -... # in production use resampling to generate sub-resolution images -... for level in range(subresolutions): -... mag = 2 ** (level + 1) -... tif.write( -... data[..., ::mag, ::mag, :], -... subfiletype=1, -... resolution=(1e4 / mag / pixelsize, 1e4 / mag / pixelsize), -... **options, -... ) -... # add a thumbnail image as a separate series -... # it is recognized by QuPath as an associated image -... thumbnail = (data[0, 0, ::8, ::8] >> 2).astype('uint8') -... tif.write(thumbnail, metadata={'Name': 'thumbnail'}) -... +.. code-block:: python + + >>> data = numpy.random.randint(0, 255, (8, 2, 512, 512, 3), 'uint8') + >>> subresolutions = 2 + >>> pixelsize = 0.29 # micrometer + >>> with TiffWriter('temp.ome.tif', bigtiff=True) as tif: + ... metadata = { + ... 'axes': 'TCYXS', + ... 'SignificantBits': 8, + ... 'TimeIncrement': 0.1, + ... 'TimeIncrementUnit': 's', + ... 'PhysicalSizeX': pixelsize, + ... 'PhysicalSizeXUnit': 'µm', + ... 'PhysicalSizeY': pixelsize, + ... 'PhysicalSizeYUnit': 'µm', + ... 'Channel': {'Name': ['Channel 1', 'Channel 2']}, + ... 'Plane': {'PositionX': [0.0] * 16, 'PositionXUnit': ['µm'] * 16}, + ... } + ... options = dict( + ... photometric='rgb', + ... tile=(128, 128), + ... compression='jpeg', + ... resolutionunit='CENTIMETER', + ... maxworkers=2, + ... ) + ... tif.write( + ... data, + ... subifds=subresolutions, + ... resolution=(1e4 / pixelsize, 1e4 / pixelsize), + ... metadata=metadata, + ... **options, + ... ) + ... # write pyramid levels to the two subifds + ... # in production use resampling to generate sub-resolution images + ... for level in range(subresolutions): + ... mag = 2 ** (level + 1) + ... tif.write( + ... data[..., ::mag, ::mag, :], + ... subfiletype=1, + ... resolution=(1e4 / mag / pixelsize, 1e4 / mag / pixelsize), + ... **options, + ... ) + ... # add a thumbnail image as a separate series + ... # it is recognized by QuPath as an associated image + ... thumbnail = (data[0, 0, ::8, ::8] >> 2).astype('uint8') + ... tif.write(thumbnail, metadata={'Name': 'thumbnail'}) + ... Access the image levels in the pyramidal OME-TIFF file: ->>> baseimage = imread('temp.ome.tif') ->>> second_level = imread('temp.ome.tif', series=0, level=1) ->>> with TiffFile('temp.ome.tif') as tif: -... baseimage = tif.series[0].asarray() -... second_level = tif.series[0].levels[1].asarray() -... +.. code-block:: python + + >>> baseimage = imread('temp.ome.tif') + >>> second_level = imread('temp.ome.tif', series=0, level=1) + >>> with TiffFile('temp.ome.tif') as tif: + ... baseimage = tif.series[0].asarray() + ... second_level = tif.series[0].levels[1].asarray() + ... number_levels = len(tif.series[0].levels) # includes base level + ... Iterate over and decode single JPEG compressed tiles in the TIFF file: ->>> with TiffFile('temp.ome.tif') as tif: -... fh = tif.filehandle -... for page in tif.pages: -... for index, (offset, bytecount) in enumerate( -... zip(page.dataoffsets, page.databytecounts) -... ): -... _ = fh.seek(offset) -... data = fh.read(bytecount) -... tile, indices, shape = page.decode( -... data, index, jpegtables=page.jpegtables -... ) -... +.. code-block:: python + + >>> with TiffFile('temp.ome.tif') as tif: + ... fh = tif.filehandle + ... for page in tif.pages: + ... for index, (offset, bytecount) in enumerate( + ... zip(page.dataoffsets, page.databytecounts) + ... ): + ... _ = fh.seek(offset) + ... data = fh.read(bytecount) + ... tile, indices, shape = page.decode( + ... data, index, jpegtables=page.jpegtables + ... ) + ... Use Zarr to read parts of the tiled, pyramidal images in the TIFF file: ->>> import zarr ->>> store = imread('temp.ome.tif', aszarr=True) ->>> z = zarr.open(store, mode='r') ->>> z - ->>> z[0] # base layer - ->>> z[0][2, 0, 128:384, 256:].shape # read a tile from the base layer -(256, 256, 3) ->>> store.close() +.. code-block:: python + + >>> import zarr + >>> store = imread('temp.ome.tif', aszarr=True) + >>> z = zarr.open(store, mode='r') + >>> z + + >>> z[0] # base layer + + >>> z[0][2, 0, 128:384, 256:].shape # read a tile from the base layer + (256, 256, 3) + >>> store.close() Load the base layer from the Zarr store as a dask array: ->>> import dask.array ->>> store = imread('temp.ome.tif', aszarr=True) ->>> dask.array.from_zarr(store, 0) -dask.array<...shape=(8, 2, 512, 512, 3)...chunksize=(1, 1, 128, 128, 3)... ->>> store.close() +.. code-block:: python + + >>> import dask.array + >>> store = imread('temp.ome.tif', aszarr=True) + >>> dask.array.from_zarr(store, 0) + dask.array<...shape=(8, 2, 512, 512, 3)...chunksize=(1, 1, 128, 128, 3)... + >>> store.close() Write the Zarr store to a fsspec ReferenceFileSystem in JSON format: ->>> store = imread('temp.ome.tif', aszarr=True) ->>> store.write_fsspec('temp.ome.tif.json', url='file://') ->>> store.close() +.. code-block:: python + + >>> store = imread('temp.ome.tif', aszarr=True) + >>> store.write_fsspec('temp.ome.tif.json', url='file://') + >>> store.close() Open the fsspec ReferenceFileSystem as a Zarr group: ->>> import fsspec ->>> import imagecodecs.numcodecs ->>> imagecodecs.numcodecs.register_codecs() ->>> mapper = fsspec.get_mapper( -... 'reference://', fo='temp.ome.tif.json', target_protocol='file' -... ) ->>> z = zarr.open(mapper, mode='r') ->>> z - +.. code-block:: python + + >>> import fsspec + >>> import imagecodecs.numcodecs + >>> imagecodecs.numcodecs.register_codecs() + >>> mapper = fsspec.get_mapper( + ... 'reference://', fo='temp.ome.tif.json', target_protocol='file' + ... ) + >>> z = zarr.open(mapper, mode='r') + >>> z + Create an OME-TIFF file containing an empty, tiled image series and write to it via the Zarr interface (note: this does not work with compression): ->>> imwrite( -... 'temp.ome.tif', -... shape=(8, 800, 600), -... dtype='uint16', -... photometric='minisblack', -... tile=(128, 128), -... metadata={'axes': 'CYX'}, -... ) ->>> store = imread('temp.ome.tif', mode='r+', aszarr=True) ->>> z = zarr.open(store, mode='r+') ->>> z - ->>> z[3, 100:200, 200:300:2] = 1024 ->>> store.close() +.. code-block:: python + + >>> imwrite( + ... 'temp.ome.tif', + ... shape=(8, 800, 600), + ... dtype='uint16', + ... photometric='minisblack', + ... tile=(128, 128), + ... metadata={'axes': 'CYX'}, + ... ) + >>> store = imread('temp.ome.tif', mode='r+', aszarr=True) + >>> z = zarr.open(store, mode='r+') + >>> z + + >>> z[3, 100:200, 200:300:2] = 1024 + >>> store.close() Read images from a sequence of TIFF files as NumPy array using two I/O worker threads: ->>> imwrite('temp_C001T001.tif', numpy.random.rand(64, 64)) ->>> imwrite('temp_C001T002.tif', numpy.random.rand(64, 64)) ->>> image_sequence = imread( -... ['temp_C001T001.tif', 'temp_C001T002.tif'], ioworkers=2, maxworkers=1 -... ) ->>> image_sequence.shape -(2, 64, 64) ->>> image_sequence.dtype -dtype('float64') +.. code-block:: python + + >>> imwrite('temp_C001T001.tif', numpy.random.rand(64, 64)) + >>> imwrite('temp_C001T002.tif', numpy.random.rand(64, 64)) + >>> image_sequence = imread( + ... ['temp_C001T001.tif', 'temp_C001T002.tif'], ioworkers=2, maxworkers=1 + ... ) + >>> image_sequence.shape + (2, 64, 64) + >>> image_sequence.dtype + dtype('float64') Read an image stack from a series of TIFF files with a file name pattern as NumPy or Zarr arrays: ->>> image_sequence = TiffSequence('temp_C0*.tif', pattern=r'_(C)(\d+)(T)(\d+)') ->>> image_sequence.shape -(1, 2) ->>> image_sequence.axes -'CT' ->>> data = image_sequence.asarray() ->>> data.shape -(1, 2, 64, 64) ->>> store = image_sequence.aszarr() ->>> zarr.open(store, mode='r') - ->>> image_sequence.close() +.. code-block:: python + + >>> image_sequence = TiffSequence('temp_C0*.tif', pattern=r'_(C)(\d+)(T)(\d+)') + >>> image_sequence.shape + (1, 2) + >>> image_sequence.axes + 'CT' + >>> data = image_sequence.asarray() + >>> data.shape + (1, 2, 64, 64) + >>> store = image_sequence.aszarr() + >>> zarr.open(store, mode='r') + + >>> image_sequence.close() Write the Zarr store to a fsspec ReferenceFileSystem in JSON format: ->>> store = image_sequence.aszarr() ->>> store.write_fsspec('temp.json', url='file://') +.. code-block:: python + + >>> store = image_sequence.aszarr() + >>> store.write_fsspec('temp.json', url='file://') Open the fsspec ReferenceFileSystem as a Zarr array: ->>> import fsspec ->>> import tifffile.numcodecs ->>> tifffile.numcodecs.register_codec() ->>> mapper = fsspec.get_mapper( -... 'reference://', fo='temp.json', target_protocol='file' -... ) ->>> zarr.open(mapper, mode='r') - +.. code-block:: python + + >>> import fsspec + >>> import tifffile.numcodecs + >>> tifffile.numcodecs.register_codec() + >>> mapper = fsspec.get_mapper( + ... 'reference://', fo='temp.json', target_protocol='file' + ... ) + >>> zarr.open(mapper, mode='r') + Inspect the TIFF file from the command line:: - $ python -m tifffile temp.ome.tif + $ python -m tifffile temp.ome.tif \ No newline at end of file