--- title: "Introduction to `romeo`" date: "`r BiocStyle::doc_date()`" author: - name: Hugo Gruson affiliation: EMBL Heidelberg email: hugo.gruson@embl.de - name: Artür Manukyan affiliation: MDC-BIMSB email: artur-man@hotmail.com package: "`r BiocStyle::pkg_ver('romeo')`" vignette: > %\VignetteIndexEntry{Introduction to romeo} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} output: BiocStyle::html_document --- # Introduction ## romeo `r BiocStyle::Biocpkg("romeo")` is a minimal R package that provides tools to read, validate, and write multiscale images and labels (regions, segmentation masks, etc.) stored as **OME-Zarr** files. The package uses the `r BiocStyle::Biocpkg("Rarr")` package to manipulate images stored as Zarr datasets and OME-Zarr metadata while the `r BiocStyle::Biocpkg("ZarrArray")` package is used to lazily read larger-than-memory images. `r BiocStyle::Biocpkg("romeo")` realizes these Zarr-backed images (or labels) as objects of an `ome_zarr` class where a number of methods are available to manipulate these images as traditional arrays. These are, for example, subsetting or slicing the images using the `[` operator which is applied to all levels of the multiscale OME-Zarr object (i.e. image pyramids). ## What is OME-Zarr? OME-Zarr is a cloud-friendly data format for storing large bioimaging datasets, such as microscopy images. It combines: * **(i)** **Zarr**, a chunked, compressed array storage format () designed for scalable access to multidimensional data and * **(ii)** **OME Next-Generation File Formats**, or **OME-NGFF** (), that defines standardized structures and metadata conventions for multiscale labels, segmentations, and coordinate transformations of bioimaging datasets. In essence, an OME-Zarr file is a collection of data arrays with XYZCT dimensions (X, Y, and Z for space, C for channels and T for time) representing an image pyramid, combined with metadata (which lives in the attributes property of Zarr arrays) that describes the properties of these arrays, such as scales, annotations and coordinate spaces (Figure 1). There exists multiple OME-Zarr formats each having its own [OME-NGFF specifications](https://ngff.openmicroscopy.org/specifications/index.html#) (Versions 0.4, 0.5, 0.6, etc.) and [Zarr formats](https://zarr-specs.readthedocs.io/en/latest/specs.html) (Versions 2 or 3). Currently, `r BiocStyle::Biocpkg("romeo")` provides utilities for manipulating OME-Zarr datasets using NGFF versions 0.4 and 0.5, as well as limited support for the transitional version 0.5-dev-spatialdata. The current released version of the OME-Zarr specification is 0.5. See [https://ngff.openmicroscopy.org/specifications](https://ngff.openmicroscopy.org/specifications) for more information. :::: {style="display: grid; grid-template-columns: 200px min-content 1fr; grid-column-gap: 10px;"} ::: {} ![](chunks.svg) ::: ::: {style="font-size: 0.75em; color: #555; overflow-x: scroll; max-width: 70%;"} ```{r, echo = FALSE, comment = ""} system.file("figures", "metadata.json", package = "romeo") |> readLines() |> cat(sep = "\n") ``` ::: :::: # Installation You can install the development version of `r BiocStyle::Biocpkg("romeo")` like so: ```{r install, eval=FALSE} install.packages("pak") pak::pak("Huber-group-EMBL/romeo") ``` # Reading OME-Zarr files ## Images This is a basic example which shows you how to read an OME-Zarr image. By default, data are read lazily using `ZarrArray`. Here, the `ome_read()` function first validates that the attributes of the OME-Zarr image comply with the relevant OME-NGFF specifications (version 0.4 in this example). If valid, it proceeds to read the data as a multi-scale `ome_zarr` object. ```{r read} library(romeo) library(utils) omezarrzip <- system.file( "extdata", "test_ngff_image_v04.ome.zarr.zip", package = "romeo" ) td <- withr::local_tempfile(fileext = ".ome.zarr") dir.create(td) unzip(omezarrzip, exdir = td) x <- ome_read(td) plot(x, 1) ``` We can extract each layer of the image pyramid using `[[` method. Each layer of the image pyramid is a `ZarrArray` object. ```{r read_layer} y <- x[[1]] is(y) ``` Alternatively, the data can be read into memory as below using the `lazy` argument: ```{r read_lazy} x <- ome_read(td, lazy = FALSE) y <- x[[1]] is(y) ``` In this case, each layer of the image pyramid is a traditional array stored in memory. ## Labels Labels of an image (or image pyramid) are pixel-level annotations that are used to annotate regions within the image (pathology annotations, segmentation masks etc.) where each pixel stores an integer value corresponding of each label. Labels of OME-Zarr images are often found nested within the zarr group of the image, at the same level of the Zarr hierarchy as the resolution levels for the original image. Each label has its own group under the `labels` group. ```{r read_label_files} omezarrzip <- system.file( "extdata", "test_ngff_image_v04.ome.zarr.zip", package = "romeo" ) td <- withr::local_tempfile(fileext = ".ome.zarr") dir.create(td) unzip(omezarrzip, exdir = td) list.files(td) list.files(file.path(td, "labels")) ``` Once located the path of the label pyramid within the OME-Zarr file, we can use `r BiocStyle::Biocpkg("romeo")` again to read these labels as `ome_zarr` objects. ```{r read_label} x <- ome_read(file.path(td, "labels/blobs")) plot(x, all = TRUE) ``` # Reading from S3 storage For remote OME-Zarr files, you can an S3 URL to `ome_read()` to read the data directly from the S3 bucket without downloading it first: ```{r read_remote} x <- ome_read( "https://uk1s3.embassy.ebi.ac.uk/idr/zarr/v0.4/idr0076A/10501752.zarr" ) ``` For more advanced cases where authentication is required to access the data, you must manually create an `s3_client` object using the `r BiocStyle::CRANpkg("paws")` package and pass it to `ome_read()`. Slicing (or subsetting) of images are performed using the `[` operator where indices correspond to each available XYZCT dimensions. ```{r read_remote_slice} attr(x, "dim_names") plot(x[1:2, 1:50, 1:50]) ``` # Writing OME-Zarr files ## Images `r BiocStyle::Biocpkg("romeo")` provides extensive utilities for writing OME-Zarr images compatible with multiple [OME-NGFF specifications](https://ngff.openmicroscopy.org/specifications/index.html#). Here, `ome_write()` function accepts objects of `Image` class (from `r BiocStyle::Biocpkg("EBImage")` package) as input. ```{r ebimage} library(EBImage) img_file <- system.file("extdata", "example_RGB.png", package = "romeo") img <- readImage(img_file) img ``` Currently, `r BiocStyle::Biocpkg("romeo")` supports the two most recent OME-NGFF specs, Versions 0.4 and 0.5, corresponding to Zarr formats v2 and v3, respectively. When writing the pyramid, we define the version, e.g. [0.4](https://ngff.openmicroscopy.org/specifications/0.4/index.html), and also the image axes, e.g. `c("x", "y", "c")`, whose order and length should match the `Image` object. ```{r write} ome_img <- ome_write( img, path = tempfile(fileext = ".ome.zarr"), axes = c("x", "y", "c"), version = "0.4", storage_options = list(chunk_dim = c(64, 64, 1)) ) plot(ome_img, 1) ``` Users can also define their own scaling factors to write image pyramids. For a `scalefactors` vector with length three, the resulting pyramid will contain four scales. Each scale factor in the vector defines the scale factor of the layer relative to the previous layer. ```{r write2} ome_img <- ome_write( img, path = tempfile(fileext = ".ome.zarr"), axes = c("x", "y", "c"), version = "0.5", scalefactors = c(2, 2, 3), storage_options = list(chunk_dim = c(64, 64, 1)) ) ``` ## Labels OME-Zarr label pyramids can be generated in the same way. We first create our own label data using `r BiocStyle::Biocpkg("EBImage")`. ```{r image-label} # read the first frame of the Image object nuc <- readImage(system.file("images", "nuclei.tif", package = "EBImage")) nuc <- getFrames(nuc)[[1]] # threshold using otsu's method nuc_th <- nuc > otsu(nuc) nuc_th ``` We can now write the label pyramid. The arguments are similar to those used for writing image pyramids, but when `type = "label"` is specified, [OME-NGFF label specifications](https://ngff.openmicroscopy.org/specifications/0.4/index.html#labels-metadata) is used to write the Zarr attributes. ```{r write_label} ome_nuc_th <- ome_write( nuc_th, path = tempfile(fileext = ".ome.zarr"), version = "0.4", scalefactors = c(2, 2, 3), storage_options = list(chunk_dim = c(64, 64)), type = "label" ) plot(ome_nuc_th, 3) ``` If the path already includes an image pyramid, then we should define a name (e.g. `blobs`) for the label pyramid associated with the image. ```{r write_image_label} td <- tempfile(fileext = ".ome.zarr") ome_nuc <- ome_write( nuc, path = td, version = "0.4", storage_options = list(chunk_dim = c(64, 64)) ) ome_nuc_th <- ome_write( nuc_th, path = td, version = "0.4", scalefactors = c(2, 2, 3), storage_options = list(chunk_dim = c(64, 64)), type = "label", label_name = "blobs" ) ``` We can now visualize both the image and its corresponding labels side by side. ```{r write_image_label_plot} layout(matrix(1:2, nrow = 1)) plot(ome_nuc, 3) plot(ome_nuc_th, 3) ``` Additional metadata information about labels can also be provided using the `label_metadata` argument, e.g. colors, properties etc. See [OME-NGFF image-label specifications](https://ngff.openmicroscopy.org/specifications/0.4/index.html#image-label-metadata) for more information. ```{r write_label_meta} ome_nuc_th <- ome_write( nuc_th, path = tempfile(fileext = ".ome.zarr"), version = "0.4", scalefactors = c(2, 2, 3), storage_options = list(chunk_dim = c(64, 64)), type = "label", label_name = "blobs", label_metadata = list( colors = list( list(`label-value` = 1, rgba = list(255, 255, 255, 255)), list(`label-value` = 2, rgba = list(0, 255, 255, 128)) ), properties = list( list(`label-value` = 1, class = "A"), list(`label-value` = 2, class = "B") ) ) ) ``` # Appendix ## Session info {.unnumbered} ```{r, session-info, echo = FALSE} sessionInfo() ```