OME_ZARR

Viewing of ome zarr file

Viewing of ome_zarr in a directory or as a zip file.

1.Open Napari with command napari

2.Open the command widget with button at the bottom left corner of the window.

3.After that, type in the command window to invoke functions that add more images as layers. To view an ome-zarr file this way with cvpl_tools, use the command

import cvpl_tools.ome_zarr.napari.add as napari_add_ome_zarr
napari_add_ome_zarr.subarray_from_path(viewer, "/absolute/path/to/your/ome.zarr", kwargs=dict(name="displayed_name_in_ui"))
  • This will create a new layer named displayed_name_in_ui which displays your ome zarr array. subarray uses Napari’s add_image function’s multiscale argument for this, which loads different resolution based on viewer’s current zoom factor

  • To open a .zip file, specify ome.zarr.zip in the path (and optionally set use_zip=True to open the file as zip regardless of its suffix)

  • To open both the ome.zarr file and any label files located at ome.zarr/labels/label_name as specified by the ome zarr standard, use cvpl_zarr.add_ome_zarr_group_from_path instead.

  • To specify additional arguments passed to Napari’s add_image function, pass your arguments in the kwargs as a dictionary.

  • An extra argument is_label can be passed into the function via kwargs dictionary. This is a boolean value that specifies whether to use viewer.add_labels (if True) or viewer.add_image (if False) function. This is useful for displaying instance segmentaion masks, where each segmented object has a distinct color.

The zip loading feature does not work with remote location on gcs, because of the limitations of ZipStore.

Reading and Writing ome zarr files

Before talking about the read and write, we need to first understand the directory structure of an ome zarr file. A basic ome zarr file (which is what we work with) is a directory that looks like the following:

- image.OME.ZARR/  # The ome zarr image, which is a directory in Windows/Linux
    - 0/  # The original image, in ZARR format
        + 0/  # Slice of image at first axis Z=0
        + 1/
        ...
        .zarray  # .zarray is meta attribute for the ZARR image
    + 1/  # Downsampled image at downsample level 1, in ZARR format
    + 2/
    + 3/
    + 4/  # The smallest downsampled image at level 4, in ZARR format
    .zattrs  # .zattrs and .zgroup are meta attributes for the ome zarr image
    .zgroup

Above + denotes collapsed folder and - denotes expanded folder. A few things to note here:

  • An image does not have to end with .OME.ZARR suffix

  • The image is not multiscaled if the maximum downsample level is 0 instead of 4, in which case there will only be one 0/ folder

  • An ome zarr image is easily confused with a ZARR image. An ome zarr image is not a standard ZARR directory and contains no .zarray meta file. Loading an ome zarr image as ZARR will crash if you forget to specify 0/ subfolder as the path to load

  • When saved as a zip file instead of a directory, the directory structure is the same except that the root is zipped. Loading a zipped ome zarr, cvpl_tools uses ZipStore’s features to directly reading individual chunks without having to unpack the entire zip file. However, writing to a ZipStore is not supported, due to lack of support by either Python’s zarr or the ome-zarr library.

  • An HPC system like Compute Canada may work better with one large files than many small files, thus the result should be zipped. This can be done by first writing the folder to somewhere that allows creating many small files and then zip the result into a single zip in the target directory

  • As of the time of writing (2024.8.14), ome-zarr library’s Writer class has a double computation issue. To temporary patch this for our use case, I’ve added a write_ome_zarr_image function to write a dask array as an ome zarr file. This function also adds support for reading images stored as a .zip file.

See the API page for cvpl_tools.ome_zarr.io.py for how to read and write OME ZARR files if you want to use cvpl_tools for such tasks. This file provides two functions load_zarr_group_from_path and write_ome_zarr_image which allows you to read and write OME ZARR files, respectively.

Specifying slices in path

cvpl_tools allows specifying the channel, or x/y/z slices to use in the path string when reading or viewing an ome zarr file for convenience.

The functions cvpl_tools.ome_zarr.io.load_dask_array_from_path, and cvpl_tools.ome_zarr.napari.add.group_from_path/subarray_from_path support specifying the slices in the following syntax, much similar to torch or numpy array slicing:

arr_original = load_dask_array_from_path('file.ome.zarr', level=0)  # shape=(2, 200, 1000, 1000)
arr1 = load_dask_array_from_path('file.ome.zarr?slices=[0]', level=0)  # shape=(200, 1000, 1000)
arr2 = load_dask_array_from_path('file.ome.zarr?slices=[:, :100]', level=0)  # shape=(2, 100, 1000, 1000)
arr3 = load_dask_array_from_path('file.ome.zarr?slices=[0:1, 0, -1:, ::2]', level=0)  # shape=(1, 1, 500)

The idea of this syntax attributes to Davis Bennett (see this discussion).

Why do we need to specify slices this way? Commonly, we pass in an ome zarr path to specify the input image of a script. If we want to run the script on the first channel of a multi-channel image, both a path to ome zarr and an in_channel integer specifying the channel to use are needed. With this syntax, we only need one input variable to specify the channel to use, as well as a sub-region of the image if we want to crop the input.