Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion ngff_zarr/from_ngff_zarr.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,15 @@ def from_ngff_zarr(

metadata.pop("@type", None)
axes = [Axis(**axis) for axis in metadata["axes"]]
coordinateTransformations = None
if "coordinateTransformations" in metadata:
coordinateTransformations = metadata["coordinateTransformations"]
metadata = Metadata(
axes=axes, datasets=datasets, name=name, version=metadata["version"]
axes=axes,
datasets=datasets,
name=name,
version=metadata["version"],
coordinateTransformations=coordinateTransformations,
)

return Multiscales(images, metadata)
7 changes: 6 additions & 1 deletion ngff_zarr/to_multiscales.py
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,11 @@ def to_multiscales(
path=path, coordinateTransformations=coordinateTransformations
)
datasets.append(dataset)
metadata = Metadata(axes=axes, datasets=datasets, name=ngff_image.name)
metadata = Metadata(
axes=axes,
datasets=datasets,
name=ngff_image.name,
coordinateTransformations=None,
)

return Multiscales(images, metadata, scale_factors, method, out_chunks)
12 changes: 12 additions & 0 deletions ngff_zarr/to_ngff_zarr.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,17 @@
from .to_multiscales import to_multiscales


def _pop_metadata_optionals(metadata_dict):
for ax in metadata_dict["axes"]:
if ax["unit"] is None:
ax.pop("unit")

if metadata_dict["coordinateTransformations"] is None:
metadata_dict.pop("coordinateTransformations")

return metadata_dict


def to_ngff_zarr(
store: Union[MutableMapping, str, Path, BaseStore],
multiscales: Multiscales,
Expand Down Expand Up @@ -55,6 +66,7 @@ def to_ngff_zarr(
"""

metadata_dict = asdict(multiscales.metadata)
metadata_dict = _pop_metadata_optionals(metadata_dict)
metadata_dict["@type"] = "ngff:Image"
root = zarr.group(store, overwrite=overwrite, chunk_store=chunk_store)
root.attrs["multiscales"] = [metadata_dict]
Expand Down
9 changes: 7 additions & 2 deletions ngff_zarr/zarr_metadata.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from dataclasses import dataclass, field
from dataclasses import dataclass
from typing import List, Optional, Union

from typing_extensions import Literal
Expand Down Expand Up @@ -139,6 +139,11 @@ class Axis:
unit: Optional[Units] = None


@dataclass
class Identity:
type: str = "identity"


@dataclass
class Scale:
scale: List[float]
Expand All @@ -164,6 +169,6 @@ class Dataset:
class Metadata:
axes: List[Axis]
datasets: List[Dataset]
coordinateTransformations: Optional[List[Transform]]
name: str = "image"
version: str = "0.4"
coordinateTransformations: List[Transform] = field(default_factory=list)
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ test = [
"itk-io>=5.3.0",
"itk-filtering>=5.3.0",
"tifffile",
"jsonschema",
]


Expand Down
12 changes: 6 additions & 6 deletions test/_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
from ngff_zarr import itk_image_to_ngff_image, to_ngff_zarr
from zarr.storage import DirectoryStore, MemoryStore

test_data_ipfs_cid = "bafybeidycdocaf7muhwt73m6vxfeaxfidbq7prvnhgn4tzrpxmpui5rila"
test_data_sha256 = "675a2cb532cb6fbabfd2b1e19f26f05b059ac51f0b611eed1164d8dd1a22e4cb"
test_data_ipfs_cid = "bafybeifkrfjreee5e7rfoi2ka3t2n23jlqwsrqwg4gmbyqcrc47iet27km"
test_data_sha256 = "861dd3acb8391a3ac2b10b3487c33ee74da1415ef30b9f4c37c7f8f49e802c32"

test_dir = Path(__file__).resolve().parent
extract_dir = "data"
Expand Down Expand Up @@ -67,14 +67,14 @@ def store_equals(baseline_store, test_store):
test_keys = set(test_store.keys())
if baseline_keys != test_keys:
sys.stderr.write("test keys != baseline keys\n")
sys.stderr.write("baseline - test:", baseline_keys.difference(test_keys), "\n")
sys.stderr.write("test - baseline:", test_keys.difference(baseline_keys), "\n")
sys.stderr.write(f"baseline - test: {baseline_keys.difference(test_keys)}, \n")
sys.stderr.write(f"test - baseline: {test_keys.difference(baseline_keys)}, \n")
return False
for k in baseline_keys:
if baseline_store[k] != test_store[k]:
sys.stderr.write(f"test value != baseline value for key {k}\n")
sys.stderr.write("baseline:", baseline_store[k], "\n")
sys.stderr.write("test:", test_store[k], "\n")
sys.stderr.write(f"baseline: {baseline_store[k]}, \n")
sys.stderr.write(f"test: {test_store[k]}, \n")
return False
return True

Expand Down
10 changes: 0 additions & 10 deletions test/test_from_ngff_zarr.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from dask_image import imread
from ngff_zarr import (
Methods,
from_ngff_zarr,
to_multiscales,
to_ngff_image,
Expand All @@ -11,15 +10,6 @@
from ._data import test_data_dir, verify_against_baseline


def test_gaussian_isotropic_scale_factors(input_images):
dataset_name = "cthead1"
image = input_images[dataset_name]
baseline_name = "2_4/DASK_IMAGE_GAUSSIAN.zarr"
multiscales = to_multiscales(image, [2, 4], method=Methods.DASK_IMAGE_GAUSSIAN)
# store_new_multiscales(dataset_name, f'{baseline_name}', multiscales)
verify_against_baseline(dataset_name, baseline_name, multiscales)


def test_from_ngff_zarr(input_images):
dataset_name = "lung_series"
data = imread.imread(input_images[dataset_name])
Expand Down
3 changes: 3 additions & 0 deletions test/test_large_serialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@


def test_large_image_serialization(input_images):
default_mem_target = config.memory_target
config.memory_target = int(1e6)

dataset_name = "lung_series"
Expand All @@ -21,3 +22,5 @@ def test_large_image_serialization(input_images):
test_store = MemoryStore(dimension_separator="/")
to_ngff_zarr(test_store, multiscales)
# verify_against_baseline(dataset_name, baseline_name, multiscales)

config.memory_target = default_mem_target
76 changes: 76 additions & 0 deletions test/test_ngff_validation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import json
from typing import Dict

import numpy as np
import urllib3
import zarr
from jsonschema import Draft202012Validator
from ngff_zarr import Multiscales, to_multiscales, to_ngff_zarr
from referencing import Registry, Resource

HTTP = urllib3.PoolManager()

NGFF_URI = "https://ngff.openmicroscopy.org"


def load_schema(version: str = "0.4", strict: bool = False) -> Dict:
strict_str = ""
if strict:
strict_str = "strict_"
response = HTTP.request(
"GET", f"{NGFF_URI}/{version}/schemas/{strict_str}image.schema"
)
return json.loads(response.data.decode())


def check_valid_ngff(multiscale: Multiscales):
store = zarr.storage.MemoryStore(dimension_separator="/")
store = zarr.storage.DirectoryStore("/tmp/test.zarr", dimension_separator="/")
to_ngff_zarr(store, multiscale)
zarr.convenience.consolidate_metadata(store)
metadata = json.loads(store.get(".zmetadata"))["metadata"]
ngff = metadata[".zattrs"]

image_schema = load_schema(version="0.4", strict=False)
# strict_image_schema = load_schema(version="0.4", strict=True)
registry = Registry().with_resource(
NGFF_URI, resource=Resource.from_contents(image_schema)
)
validator = Draft202012Validator(image_schema, registry=registry)
# registry_strict = Registry().with_resource(NGFF_URI, resource=Resource.from_contents(strict_image_schema))
# strict_validator = Draft202012Validator(strict_schema, registry=registry_strict)

validator.validate(ngff)
# Need to add NGFF metadata property
# strict_validator.validate(ngff)


def test_y_x_valid_ngff():
array = np.random.random((32, 16))
multiscale = to_multiscales(array, [2, 4])

check_valid_ngff(multiscale)


# def test_z_y_x_valid_ngff():
# array = np.random.random((32, 32, 16))
# image = to_spatial_image(array)
# multiscale = to_multiscale(image, [2, 4])

# check_valid_ngff(multiscale)


# def test_z_y_x_c_valid_ngff():
# array = np.random.random((32, 32, 16, 3))
# image = to_spatial_image(array)
# multiscale = to_multiscale(image, [2, 4])

# check_valid_ngff(multiscale)


# def test_t_z_y_x_c_valid_ngff():
# array = np.random.random((2, 32, 32, 16, 3))
# image = to_spatial_image(array)
# multiscale = to_multiscale(image, [2, 4])

# check_valid_ngff(multiscale)
3 changes: 3 additions & 0 deletions test/test_to_ngff_zarr_dask_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,13 @@ def test_gaussian_isotropic_scale_factors(input_images):
multiscales = to_multiscales(image, method=Methods.DASK_IMAGE_GAUSSIAN)
verify_against_baseline(dataset_name, baseline_name, multiscales)


def test_gaussian_isotropic_scale_factors_two_components(input_images):
dataset_name = "brain_two_components"
image = input_images[dataset_name]
baseline_name = "2_4/DASK_IMAGE_GAUSSIAN.zarr"
multiscales = to_multiscales(image, [2, 4], method=Methods.DASK_IMAGE_GAUSSIAN)
# store_new_multiscales(dataset_name, baseline_name, multiscales)
verify_against_baseline(dataset_name, baseline_name, multiscales)


Expand Down