diff --git a/docs/array_api.md b/docs/array_api.md new file mode 100644 index 0000000..d50606d --- /dev/null +++ b/docs/array_api.md @@ -0,0 +1,167 @@ +# 🐍 Python Array API + +NGFF-Zarr supports conversion of any NumPy array-like object that follows the +[Python Array API Standard](https://data-apis.org/array-api/latest/) into +OME-Zarr. This includes such objects an NumPy `ndarray`'s, Dask Arrays, PyTorch +Tensors, CuPy arrays, Zarr array, etc. + +## Array to NGFF Image + +Convert the array to an `NgffImage`, which is a standard +[Python dataclass](https://docs.python.org/3/library/dataclasses.html) that +represents an OME-Zarr image for a single scale. + +When creating the image from the array, you can specify + +- names of the `dims` from `{‘t’, ‘z’, ‘y’, ‘x’, ‘c’}` +- the `scale`, the pixel spacing for the spatial dims +- the `translation`, the origin or offset of the center of the first pixel +- a `name` for the image +- and `axes_units` with + [UDUNITS-2 identifiers](https://ngff.openmicroscopy.org/latest/#axes-md) + +```python +>>> # Load an image as a NumPy array +>>> from imageio.v3 import imread +>>> data = imread('cthead1.png') +>>> print(type(data)) + +``` + +Specify optional additional metadata with `to_ngff_zarr`. + +```python +>>> import ngff_zarr as nz +>>> image = nz.to_ngff_image(data, + dims=['y', 'x'], + scale={'y': 1.0, 'x': 1.0}, + translation={'y': 0.0, 'x': 0.0}) +>>> print(image) +NgffImage( + data=dask.array, + dims=['y', 'x'], + scale={'y': 1.0, 'x': 1.0}, + translation={'y': 0.0, 'x': 0.0}, + name='image', + axes_units=None, + computed_callbacks=[] +) +``` + +The image data is nested in a lazy `dask.array` and chucked. + +If `dims`, `scale`, or `translation` are not specified, NumPy-compatible +defaults are used. + +## Generate multiscales + +OME-Zarr represents images in a chunked, multiscale data structure. Use +`to_multiscales` to build a task graph that will produce a chunked, multiscale +image pyramid. `to_multiscales` has optional `scale_factors` and `chunks` +parameters. An [antialiasing method](./methods.md) can also be prescribed. + +```python +>>> multiscales = nz.to_multiscales(image, + scale_factors=[2,4], + chunks=64) +>>> print(multiscales) +Multiscales( + images=[ + NgffImage( + data=dask.array, + dims=['y', 'x'], + scale={'y': 1.0, 'x': 1.0}, + translation={'y': 0.0, 'x': 0.0}, + name='image', + axes_units=None, + computed_callbacks=[] + ), + NgffImage( + data=dask.array, + dims=['y', 'x'], + scale={'x': 2.0, 'y': 2.0}, + translation={'x': 0.5, 'y': 0.5}, + name='image', + axes_units=None, + computed_callbacks=[] + ), + NgffImage( + data=dask.array, + dims=['y', 'x'], + scale={'x': 4.0, 'y': 4.0}, + translation={'x': 1.5, 'y': 1.5}, + name='image', + axes_units=None, + computed_callbacks=[] + ) + ], + metadata=Metadata( + axes=[ + Axis(name='y', type='space', unit=None), + Axis(name='x', type='space', unit=None) + ], + datasets=[ + Dataset( + path='scale0/image', + coordinateTransformations=[ + Scale(scale=[1.0, 1.0], type='scale'), + Translation( + translation=[0.0, 0.0], + type='translation' + ) + ] + ), + Dataset( + path='scale1/image', + coordinateTransformations=[ + Scale(scale=[2.0, 2.0], type='scale'), + Translation( + translation=[0.5, 0.5], + type='translation' + ) + ] + ), + Dataset( + path='scale2/image', + coordinateTransformations=[ + Scale(scale=[4.0, 4.0], type='scale'), + Translation( + translation=[1.5, 1.5], + type='translation' + ) + ] + ) + ], + coordinateTransformations=None, + name='image', + version='0.4' + ), + scale_factors=[2, 4], + method=, + chunks={'y': 64, 'x': 64} +) +``` + +The `Multiscales` dataclass stores all the images and their metadata for each +scale according the OME-Zarr data model. Note that the correct `scale` and +`translation` for each scale are automatically computed. + +## Write to Zarr + +To write the multiscales to Zarr, use `to_ngff_zarr`. + +```python +nz.to_ngff_zarr('cthead1.ome.zarr', multiscales) +``` + +Use the `.ome.zarr` extension for local directory stores by convention. + +Any other +[Zarr store type](https://zarr.readthedocs.io/en/stable/api/storage.html) can +also be used. + +The multiscales will be computed and written out-of-core, limiting memory usage. diff --git a/docs/index.md b/docs/index.md index 4e56315..19caee2 100644 --- a/docs/index.md +++ b/docs/index.md @@ -22,10 +22,11 @@ A lean and kind [OME-Zarr NGFF specification](https://github.com/ome/ngff) ```{toctree} -:maxdepth: 3 +:maxdepth: 2 quick_start.md installation.md +array_api.md cli.md methods.md development.md diff --git a/docs/installation.md b/docs/installation.md index f6d9158..18109e3 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -17,7 +17,8 @@ pip install "ngff-zarr[cli]" ```python import micropip await micropip.install('ngff-zarr') +``` + ::: :::: -``` diff --git a/docs/quick_start.md b/docs/quick_start.md index 71b19d0..d9342d1 100644 --- a/docs/quick_start.md +++ b/docs/quick_start.md @@ -12,14 +12,13 @@ pip install "ngff-zarr[cli]" ngff-zarr -i ./cthead1.png -o ./cthead1.ome.zarr ``` -## NumPy array-like to OME-Zarr +## NumPy array to OME-Zarr ```python import ngff_zarr as nz import numpy as np data = np.random.randint(0, 256, int(1e6)).reshape((1000, 1000)) -ngff_image = nz.to_ngff_image(data) -multiscales = nz.to_multiscales(ngff_image) +multiscales = nz.to_multiscales(data) nz.to_ngff_zarr('example.ome.zarr', multiscales) ``` diff --git a/ngff_zarr/to_multiscales.py b/ngff_zarr/to_multiscales.py index 3393738..13b0a60 100644 --- a/ngff_zarr/to_multiscales.py +++ b/ngff_zarr/to_multiscales.py @@ -260,6 +260,9 @@ def to_multiscales( Examples: 64 or [2, 4] or [{'x': 2, 'y': 4 }, {'x': 5, 'y': 10}] :type scale_factors: int of minimum length, int per scale or dict of spatial dimension int's per scale + :param method: Specify the anti-aliasing method used to downsample the image. Default is ITKWASM_GAUSSIAN. + :type Methods: ngff_zarr.Methods enum + :param chunks: Specify the chunking used in each output scale. :type chunks: Dask array chunking specification, optional