diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000000000000000000000000000000000000..bce638805c360b8f2052ba78c866bc95f8ebff69 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,45 @@ +[metadata] +name = zarr-tools +description = Convert nd2 to zarr +long_description = file: README.md +long_description_content_type = text/markdown +url = https://gitlab.pasteur.fr/aaristov/zarr-tools +author = Andrey Aristov +author_email = aaristov@pasteur.fr +license = BSD-3-Clause +license_file = LICENSE +classifiers = + Development Status :: 2 - Pre-Alpha + Framework :: napari + Intended Audience :: Developers + License :: OSI Approved :: BSD License + Operating System :: OS Independent + Programming Language :: Python + Programming Language :: Python :: 3 + Programming Language :: Python :: 3 :: Only + Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 + Topic :: Software Development :: Testing +project_urls = + Bug Tracker = https://gitlab.pasteur.fr/aaristov/zarr-tools/issues + +[options] +packages = find: +install_requires = + dask + fire + nd2 + zarr + +python_requires = >=3.8 +include_package_data = True +package_dir = + =src +setup_requires = + setuptools-scm + +[options.packages.find] +where = src + + diff --git a/src/zarr_tools/__init__.py b/src/zarr_tools/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc --- /dev/null +++ b/src/zarr_tools/__init__.py @@ -0,0 +1 @@ + diff --git a/src/zarr_tools/__main__.py b/src/zarr_tools/__main__.py new file mode 100644 index 0000000000000000000000000000000000000000..afdb8e63d0626d6467ba8253a3a4d8812153790d --- /dev/null +++ b/src/zarr_tools/__main__.py @@ -0,0 +1,21 @@ +from .convert import to_zarr +import fire +import nd2 +import os + +def main(nd2_path:str, output:str=None, channel_axis:int=1, steps:int=6, dry_run=False): + data = (d := nd2.ND2File(nd2_path)).to_dask().rechunk() + print(d.sizes) + try: + channel_axis = list(d.sizes.keys()).index('C') + except ValueError: + channel_axis = None + + if output is None: + output = nd2_path.replace('.nd2', '.zarr') + out = to_zarr(data, output, steps=steps, dry_run=dry_run, channel_axis=channel_axis) + assert os.path.exists(out), "Failed..." + exit(0) + +if __name__=="__main__": + fire.Fire(main) diff --git a/src/zarr_tools/convert.py b/src/zarr_tools/convert.py new file mode 100644 index 0000000000000000000000000000000000000000..5dd27c41d4f1a35bd8a3b199f019dfb6a9b989ea --- /dev/null +++ b/src/zarr_tools/convert.py @@ -0,0 +1,62 @@ +import zarr +import dask.array as da +import os +import nd2 + +def nd2_to_zarr(path_nd2, out=None, steps=6, dry_run=False): + ''' + Converts nd2 to zarr, multiscale + ''' + data = nd2.ND2File(path_nd2) + print(sizes := data.sizes) + channel_axis = list(sizes.keys()).index('C') + out = (path_nd2.replace('.nd2', '.zarr') if out is None else path_nd2) + dask_input = data.to_dask() + _ = to_zarr( + dask_input=dask_input, + path=out, + steps=steps, + channel_axis=channel_axis, + dry_run=dry_run + ) + + +def to_zarr(dask_input:da.Array, path:str=None, steps=3, channel_axis=1, dry_run=False): + store = zarr.DirectoryStore(baseurl := path.replace('.nd2', '.zarr') if path is None else path) + grp = zarr.group(store) + grp.attrs['multiscales'] = { + "multiscales": [ + { + "datasets": [ + { + "path": str(i) + } for i in range(steps) + ], + "name": os.path.basename(baseurl), + "type": "nd2", + "channel_axis": channel_axis, + "version": "0.1" + }, + + ] + } + print(baseurl) + for i in range(steps): + data = dask_input[...,::2,::2] + try: + data = data.rechunk() + print(data.chunksize, data.shape) + if not dry_run: + data.to_zarr(ppp:=os.path.join(baseurl, str(i))) + print(f'saved {ppp}') + else: + print(f'dry-run `to save to` {os.path.join(baseurl, str(i))}') + + dask_input = da.from_zarr(ppp) + except Exception as e: + print(e.args) + raise e + + return baseurl + +