ome_zarr Python library

Writing OME-NGFF images

The principle entry-point for writing OME-NGFF images is ome_zarr.writer.write_image(). This takes an n-dimensional numpy array or dask array and writes it to the specified zarr group according to the OME-NGFF specification. By default, a pyramid of resolution levels will be created by down-sampling the data by a factor of 2 in the X and Y dimensions.

Alternatively, the ome_zarr.writer.write_multiscale() can be used, which takes a “pyramid” numpy arrays.

The following code creates a 3D Image in OME-Zarr with labels:

import numpy as np
import zarr
import os

from skimage.data import binary_blobs
from ome_zarr.io import parse_url
from ome_zarr.writer import write_image

path = "test_ngff_image.zarr"
os.mkdir(path)

mean_val=10
size_xy = 128
size_z = 10
rng = np.random.default_rng(0)
data = rng.poisson(mean_val, size=(size_z, size_xy, size_xy)).astype(np.uint8)

# write the image data
store = parse_url(path, mode="w").store
root = zarr.group(store=store)
write_image(image=data, group=root, axes="zyx", storage_options=dict(chunks=(1, size_xy, size_xy)))
# optional rendering settings
root.attrs["omero"] = {
    "channels": [{
        "color": "00FFFF",
        "window": {"start": 0, "end": 20, "min": 0, "max": 255},
        "label": "random",
        "active": True,
    }]
}


# add labels...
blobs = binary_blobs(length=size_xy, volume_fraction=0.1, n_dim=3).astype('int8')
blobs2 = binary_blobs(length=size_xy, volume_fraction=0.1, n_dim=3).astype('int8')
# blobs will contain values of 1, 2 and 0 (background)
blobs += 2 * blobs2

# label.shape is (size_xy, size_xy, size_xy), Slice to match the data
label = blobs[:size_z, :, :]

# write the labels to /labels
labels_grp = root.create_group("labels")
# the 'labels' .zattrs lists the named labels data
label_name = "blobs"
labels_grp.attrs["labels"] = [label_name]
label_grp = labels_grp.create_group(label_name)
# need 'image-label' attr to be recognized as label
label_grp.attrs["image-label"] = {
    "colors": [
        {"label-value": 1, "rgba": [255, 0, 0, 255]},
        {"label-value": 2, "rgba": [0, 255, 0, 255]},
        {"label-value": 3, "rgba": [255, 255, 0, 255]}
    ]
}

write_image(label, label_grp, axes="zyx")

This image can be viewed in napari using the napari-ome-zarr plugin:

$ napari test_ngff_image.zarr

Writing HCS datasets to OME-NGFF

This sample code shows how to write a high-content screening dataset (i.e. culture plate with multiple wells) to a OME-NGFF file:

import numpy as np
import zarr

from ome_zarr.io import parse_url
from ome_zarr.writer import write_image, write_plate_metadata, write_well_metadata

path = "test_ngff_plate.zarr"
row_names = ["A", "B"]
col_names = ["1", "2", "3"]
well_paths = ["A/2", "B/3"]
field_paths = ["0", "1", "2"]

# generate data
mean_val=10
num_wells = len(well_paths)
num_fields = len(field_paths)
size_xy = 128
size_z = 10
rng = np.random.default_rng(0)
data = rng.poisson(mean_val, size=(num_wells, num_fields, size_z, size_xy, size_xy)).astype(np.uint8)

# write the plate of images and corresponding metadata
store = parse_url(path, mode="w").store
root = zarr.group(store=store)
write_plate_metadata(root, row_names, col_names, well_paths)
for wi, wp in enumerate(well_paths):
    row, col = wp.split("/")
    row_group = root.require_group(row)
    well_group = row_group.require_group(col)
    write_well_metadata(well_group, field_paths)
    for fi, field in enumerate(field_paths):
        image_group = well_group.require_group(str(field))
        write_image(image=data[wi, fi], group=image_group, axes="zyx", storage_options=dict(chunks=(1, size_xy, size_xy)))

This image can be viewed in napari using the napari-ome-zarr plugin:

import napari

viewer = napari.Viewer()
viewer.open(path, plugin="napari-ome-zarr")

Reading OME-NGFF images

This sample code reads an image stored on remote s3 server, but the same code can be used to read data on a local file system. In either case, the data is available as dask arrays:

from ome_zarr.io import parse_url
from ome_zarr.reader import Reader
import napari

url = "https://uk1s3.embassy.ebi.ac.uk/idr/zarr/v0.4/idr0062A/6001240.zarr"

# read the image data
store = parse_url(url, mode="r").store

reader = Reader(parse_url(url))
# nodes may include images, labels etc
nodes = list(reader())
# first node will be the image pixel data
image_node = nodes[0]

dask_data = image_node.data

# We can view this in napari
# NB: image axes are CZYX: split channels by C axis=0
viewer = napari.view_image(dask_data, channel_axis=0)
if __name__ == '__main__':
    napari.run()