diff --git a/latest/examples/coordSystems/arrayCoordSys.json b/latest/examples/coordSystems/arrayCoordSys.json new file mode 100644 index 00000000..9c7e1229 --- /dev/null +++ b/latest/examples/coordSystems/arrayCoordSys.json @@ -0,0 +1,10 @@ +{ + "arrayCoordinateSystem" : { + "name" : "myDataArray", + "axes" : [ + {"name": "i", "type": "array"}, + {"name": "j", "type": "array"}, + {"name": "k", "type": "array"} + ] + } +} diff --git a/latest/examples/multiscales_strict/multiscales_example.json b/latest/examples/multiscales_strict/multiscales_example.json index 73e5286c..beed1cd7 100644 --- a/latest/examples/multiscales_strict/multiscales_example.json +++ b/latest/examples/multiscales_strict/multiscales_example.json @@ -3,44 +3,50 @@ { "version": "0.5-dev", "name": "example", - "axes": [ - {"name": "t", "type": "time", "unit": "millisecond"}, - {"name": "c", "type": "channel"}, - {"name": "z", "type": "space", "unit": "micrometer"}, - {"name": "y", "type": "space", "unit": "micrometer"}, - {"name": "x", "type": "space", "unit": "micrometer"} + "coordinateSystems" : [ + { + "name" : "example", + "axes": [ + {"name": "t", "type": "time", "unit": "millisecond"}, + {"name": "c", "type": "channel"}, + {"name": "z", "type": "space", "unit": "micrometer"}, + {"name": "y", "type": "space", "unit": "micrometer"}, + {"name": "x", "type": "space", "unit": "micrometer"} + ] + } ], "datasets": [ { "path": "0", "coordinateTransformations": [{ - // the voxel size for the first scale level (0.5 micrometer) + // the voxel size for the first scale level (0.5 micrometer), time unit (0.1 milliseconds) "type": "scale", - "scale": [1.0, 1.0, 0.5, 0.5, 0.5] + "scale": [0.1, 1.0, 0.5, 0.5, 0.5], + "input" : "/0", + "output" : "example" }] }, { "path": "1", "coordinateTransformations": [{ - // the voxel size for the second scale level (downscaled by a factor of 2 -> 1 micrometer) + // the voxel size for the second scale level (downscaled by a factor of 2 -> 1 micrometer), time unit (0.1 milliseconds) "type": "scale", - "scale": [1.0, 1.0, 1.0, 1.0, 1.0] + "scale": [0.1, 1.0, 1.0, 1.0, 1.0], + "input" : "/1`", + "output" : "example" }] }, { "path": "2", "coordinateTransformations": [{ - // the voxel size for the third scale level (downscaled by a factor of 4 -> 2 micrometer) + // the voxel size for the third scale level (downscaled by a factor of 4 -> 2 micrometer), time unit (0.1 milliseconds) "type": "scale", - "scale": [1.0, 1.0, 2.0, 2.0, 2.0] + "scale": [0.1, 1.0, 2.0, 2.0, 2.0], + "input" : "/2", + "output" : "example" }] } ], - "coordinateTransformations": [{ - // the time unit (0.1 milliseconds), which is the same for each scale level - "type": "scale", - "scale": [0.1, 1.0, 1.0, 1.0, 1.0] - }], "type": "gaussian", "metadata": { "description": "the fields in metadata depend on the downscaling implementation. Here, the parameters passed to the skimage function are given", @@ -51,4 +57,4 @@ } } ] -} \ No newline at end of file +} diff --git a/latest/examples/multiscales_strict/multiscales_example_relative.json b/latest/examples/multiscales_strict/multiscales_example_relative.json new file mode 100644 index 00000000..c0b10d5b --- /dev/null +++ b/latest/examples/multiscales_strict/multiscales_example_relative.json @@ -0,0 +1,61 @@ +{ + "multiscales": [ + { + "version": "0.5-dev", + "name": "example", + "coordinateSystems" : [ + { + "name" : "exampleCoordinateSystem", + "axes": [ + {"name": "t", "type": "time", "unit": "millisecond"}, + {"name": "c", "type": "channel"}, + {"name": "z", "type": "space", "unit": "micrometer"}, + {"name": "y", "type": "space", "unit": "micrometer"}, + {"name": "x", "type": "space", "unit": "micrometer"} + ] + } + ], + "datasets": [ + { + "path": "0" + // the transformation of other arrays are defined relative to this, the highest resolution, array + }, + { + "path": "1", + "coordinateTransformations": [{ + // the second scale level (downscaled by a factor of 2 relative to "0" in zyx) + "type": "scale", + "scale": [1, 1, 2, 2, 2], + "input" : "/1`", + "output" : "/0" + }] + }, + { + "path": "2", + "coordinateTransformations": [{ + // the third scale level (downscaled by a factor of 4 relative to "0" in zyx) + "type": "scale", + "scale": [1, 1, 4, 4, 4], + "input" : "/2", + "output" : "/0" + }] + } + ], + "coordinateTransformations": [{ + // the time unit (0.1 milliseconds), the voxel size for all spatial axes of "0" (0.5 micrometers) + "type": "scale", + "scale": [0.1, 1.0, 0.5, 0.5, 0.5], + "input" : "/0", + "output" : "exampleCoordinateSystem" + }], + "type": "gaussian", + "metadata": { + "description": "the fields in metadata depend on the downscaling implementation. Here, the parameters passed to the skimage function are given", + "method": "skimage.transform.pyramid_gaussian", + "version": "0.16.1", + "args": "[true]", + "kwargs": {"multichannel": true} + } + } + ] +} diff --git a/latest/examples/subspace/subspaceMultidim.json b/latest/examples/subspace/subspaceMultidim.json new file mode 100644 index 00000000..cfbe5dae --- /dev/null +++ b/latest/examples/subspace/subspaceMultidim.json @@ -0,0 +1,64 @@ +{ + "coordinateSystems" : [ + { "name " : "in", "axes" : [ {"name" : "0", "name" : "1", "name": "2", "name": "3", "name": "4" }] }, + { "name " : "out", "axes" : [ {"name" : "x", "name" : "y", "name" : "z" }] } + ], + "coordinateTransformations" : [ + { + "type" : "sequence", + "name" : "5D-to-3D", + "input" : "in", + "output" : "out", + "transformations" : [ + { + "type": "mapIndex", + "inputAxes" : ["0", "1"], + "outputAxes" : ["x", "y"] + }, + { + "type": "scale", + "scale" : [2], + "inputAxes" : ["3"], + "outputAxes" : ["z"] + } + ] + }, + { + "type" : "sequence", + "name" : "5D-to-3D-not-contiguous", + "input" : "in", + "output" : "out", + "transformations" : [ + { + "type": "mapIndex", + "inputAxes" : ["0", "2"], + "outputAxes" : ["x", "z"] + }, + { + "type": "scale", + "scale" : [2], + "inputAxes" : ["1"], + "outputAxes" : ["y"] + } + ] + }, + { + "type" : "sequence", + "name" : "5D-to-3D-not-contiguous", + "input" : "in", + "output" : "out", + "transformations" : [ + { + "type": "mapAxes", + "map" : {"0":"x", "2":"z"} + }, + { + "type": "scale", + "scale" : [2], + "inputAxes" : ["1"], + "outputAxes" : ["y"] + } + ] + } + ] +} diff --git a/latest/examples/subspace/subspacePermute.json b/latest/examples/subspace/subspacePermute.json new file mode 100644 index 00000000..26749751 --- /dev/null +++ b/latest/examples/subspace/subspacePermute.json @@ -0,0 +1,26 @@ +{ + "coordinateSystems" : [ + { "name" : "in", "axes" : [ {"name" : "i"}, {"name" : "j" } ]}, + { "name" : "out", "axes" : [ {"name" : "x"}, {"name" : "y" } ]} + ], + "coordinateTransformations" : [ + { + "type" : "byDimension", + "input" : "in", + "output" : "out", + "transformations" : [ + { + "type": "identity", + "input" : ["j"], + "output" : ["x"] + }, + { + "type": "scale", + "scale" : [2], + "input" : ["i"], + "output" : ["y"] + } + ] + } + ] +} diff --git a/latest/examples/transformations/affine2d2d.json b/latest/examples/transformations/affine2d2d.json new file mode 100644 index 00000000..f85e3b36 --- /dev/null +++ b/latest/examples/transformations/affine2d2d.json @@ -0,0 +1,14 @@ +{ + "coordinateSystems" : [ + { "name": "ij", "axes": [{"name": "i"}, {"name": "j"}] }, + { "name": "xy", "axes": [{"name": "x"}, {"name": "y"}] } + ], + "coordinateTransformations" : [ + { + "type": "affine", + "affine": [1, 2, 3, 4, 5, 6], + "input": "ij", + "output": "xy" + } + ] +} diff --git a/latest/examples/transformations/affine2d3d.json b/latest/examples/transformations/affine2d3d.json new file mode 100644 index 00000000..be45fd1b --- /dev/null +++ b/latest/examples/transformations/affine2d3d.json @@ -0,0 +1,14 @@ +{ + "coordinateSystems": [ + { "name": "ij", "axes": [{"name": "i"}, {"name": "j"}] }, + { "name": "xyz", "axes": [{"name": "x"}, {"name": "y"}, {"name": "z"}] } + ], + "coordinateTransformations": [ + { + "type": "affine", + "affine": [1, 2, 3, 4, 5, 6, 7, 8, 9], + "input": "ij", + "output": "xyz" + } + ] +} diff --git a/latest/examples/transformations/affine2d3d_nested.json b/latest/examples/transformations/affine2d3d_nested.json new file mode 100644 index 00000000..6c0dce02 --- /dev/null +++ b/latest/examples/transformations/affine2d3d_nested.json @@ -0,0 +1,15 @@ +{ + "coordinateSystems" : [ + { "name": "ij", "axes": [{"name": "i"}, {"name": "j"}] }, + { "name": "xy", "axes": [{"name": "x"}, {"name": "y"}] } + ], + "coordinateTransformations" : [ + { + "type": "affine", + "affine": [ [1, 2, 3], + [4, 5, 6]], + "input": "ij", + "output": "xy" + } + ] +} diff --git a/latest/examples/transformations/bijection.json b/latest/examples/transformations/bijection.json new file mode 100644 index 00000000..bc74b986 --- /dev/null +++ b/latest/examples/transformations/bijection.json @@ -0,0 +1,15 @@ +{ + "coordinateSystems" : [ + { "name": "src", "axes": [{"name": "i"}, {"name": "j"}] }, + { "name": "tgt", "axes": [{"name": "x"}, {"name": "y"}] } + ], + "coordinateTransformations" : [ + { + "type": "bijection", + "forward": { "type" : "coordinates", "path" : "/forward_coordinates" }, + "inverse": { "type" : "coordinates", "path" : "/inverse_coordinates" }, + "input": "src", + "output": "tgt" + } + ] +} diff --git a/latest/examples/transformations/bijection_verbose.json b/latest/examples/transformations/bijection_verbose.json new file mode 100644 index 00000000..5eccc08e --- /dev/null +++ b/latest/examples/transformations/bijection_verbose.json @@ -0,0 +1,7 @@ +{ + "type": "bijection", + "forward": { "type" : "coordinates", "path" : "/forward_coordinates", "input" : "src", "output" : "tgt" }, + "inverse": { "type" : "coordinates", "path" : "/inverse_coordinates", "input" : "tgt", "output" : "src" }, + "input": "src", + "output": "tgt" +} diff --git a/latest/examples/transformations/byDimension1.json b/latest/examples/transformations/byDimension1.json new file mode 100644 index 00000000..a42ed37a --- /dev/null +++ b/latest/examples/transformations/byDimension1.json @@ -0,0 +1,17 @@ +{ + "coordinateSystems": [ + { "name": "in", "axes": [ {"name": "i"}, {"name": "j"} ] }, + { "name": "out", "axes": [ {"name": "x"}, {"name": "y"} ] } + ], + "coordinateTransformations": [ + { + "type": "byDimension", + "input": "in", + "output": "out", + "transformations": [ + { "type": "translation", "translation": [-1.0], "input": ["i"], "output": ["x"]}, + { "type": "scale", "scale": [2.0], "input": ["j"], "output": ["y"]} + ] + } + ] +} diff --git a/latest/examples/transformations/byDimension2.json b/latest/examples/transformations/byDimension2.json new file mode 100644 index 00000000..0568c9bd --- /dev/null +++ b/latest/examples/transformations/byDimension2.json @@ -0,0 +1,17 @@ +{ + "coordinateSystems": [ + { "name": "in", "axes": [ {"name": "i"}, {"name": "j"}, {"name": "k"}, {"name": "l"}] }, + { "name": "out", "axes": [ {"name": "x"}, {"name": "y"}, {"name": "z"} ] } + ], + "coordinateTransformations": [ + { + "type": "byDimension", + "input": "in", + "output": "out", + "transformations" : [ + { "type": "translation", "translation": [1, 3], "input": ["i", "k" ], "output": ["y", "x"]}, + { "type": "scale", "scale": [2.0], "input": ["j"], "output": ["z"]} + ] + } + ] +} diff --git a/latest/examples/transformations/byDimensionInvalid1.json b/latest/examples/transformations/byDimensionInvalid1.json new file mode 100644 index 00000000..8d3c9696 --- /dev/null +++ b/latest/examples/transformations/byDimensionInvalid1.json @@ -0,0 +1,17 @@ +{ + "coordinateSystems": [ + { "name": "in", "axes": [ {"name": "i"}, {"name": "j"} ] }, + { "name": "out", "axes": [ {"name": "x"}, {"name": "y"} ] } + ], + "coordinateTransformations": [ + { + "type": "byDimension", + "input": "in", + "output": "out", + "transformations": [ + { "type": "translation", "translation": [-1.0], "input": ["i"], "output": ["z"]}, + { "type": "scale", "scale": [2.0], "input": ["0"], "output": ["y"]} + ] + } + ] +} diff --git a/latest/examples/transformations/byDimensionInvalid2.json b/latest/examples/transformations/byDimensionInvalid2.json new file mode 100644 index 00000000..fdd3ac4b --- /dev/null +++ b/latest/examples/transformations/byDimensionInvalid2.json @@ -0,0 +1,17 @@ +{ + "coordinateSystems": [ + { "name": "in", "axes": [ {"name": "i"}, {"name": "j"} ] }, + { "name": "out", "axes": [ {"name": "x"}, {"name": "y"} ] } + ], + "coordinateTransformations": [ + { + "type": "byDimension", + "input": "in", + "output": "out", + "transformations": [ + { "type": "translation", "translation": [-1.0], "input": ["i"], "output": ["x"]}, + { "type": "scale", "scale": [2.0], "input": ["i"], "output": ["x"]} + ] + } + ] +} diff --git a/latest/examples/transformations/coordinates1d.json b/latest/examples/transformations/coordinates1d.json new file mode 100644 index 00000000..314bc6fb --- /dev/null +++ b/latest/examples/transformations/coordinates1d.json @@ -0,0 +1,14 @@ +{ + "coordinateSystems": [ + { "name": "i", "axes": [{"name": "i"}] }, + { "name": "x", "axes": [{"name": "x"}] } + ], + "coordinateTransformations": [{ + "name": "a coordinate field transform", + "type": "coordinates", + "path": "i2xCoordinates", + "input": "i", + "output": "x", + "interpolation": "nearest" + }] +} diff --git a/latest/examples/transformations/displacement1d.json b/latest/examples/transformations/displacement1d.json new file mode 100644 index 00000000..5db76446 --- /dev/null +++ b/latest/examples/transformations/displacement1d.json @@ -0,0 +1,14 @@ +{ + "coordinateSystems": [ + { "name": "i", "axes": [{"name": "i"}] }, + { "name": "x", "axes": [{"name": "x"}] } + ], + "coordinateTransformations": [{ + "name": "a displacement field transform", + "type": "displacements", + "path": "i2xCoordinates", + "input": "i", + "output": "x", + "interpolation": "nearest" + }] +} diff --git a/latest/examples/transformations/identity.json b/latest/examples/transformations/identity.json new file mode 100644 index 00000000..3ea1529a --- /dev/null +++ b/latest/examples/transformations/identity.json @@ -0,0 +1,9 @@ +{ + "coordinateSystems": [ + { "name": "in", "axes": [ {"name": "i"}, {"name": "j"} ]}, + { "name": "out", "axes": [ {"name": "x"}, {"name": "y"} ]} + ], + "coordinateTransformations": [ + { "type": "identity", "input": "in", "output": "out" } + ] +} diff --git a/latest/examples/transformations/inverseOf.json b/latest/examples/transformations/inverseOf.json new file mode 100644 index 00000000..3e2966c5 --- /dev/null +++ b/latest/examples/transformations/inverseOf.json @@ -0,0 +1,14 @@ +{ + "coordinateSystems" : [ + { "name" : "moving", "axes" : [{"name" : "x-moving"}, {"name":"y-moving"}] }, + { "name" : "fixed", "axes" : [{"name" : "x-fixed"}, {"name":"y-fixed"}] } + ], + "coordinateTransformations" : [ + { + "type": "inverseOf", + "transformation" : { "type": "displacements", "path": "/path/to/displacements" }, + "input" : "moving", + "output" : "fixed" + } + ] +} \ No newline at end of file diff --git a/latest/examples/transformations/mapAxis1.json b/latest/examples/transformations/mapAxis1.json new file mode 100644 index 00000000..2b6b0b79 --- /dev/null +++ b/latest/examples/transformations/mapAxis1.json @@ -0,0 +1,23 @@ +{ + "coordinateSystems": [ + { "name": "in", "axes": [ {"name": "i"}, {"name": "j"} ]}, + { "name": "out1", "axes": [ {"name": "x"}, {"name": "y"} ]}, + { "name": "out2", "axes": [ {"name": "x"}, {"name": "y"} ]} + ], + "coordinateTransformations": [ + { + "name": "equivalent to identity", + "type": "mapAxis", + "mapAxis": { "x":"i", "y":"j" }, + "input": "in", + "output": "out1" + }, + { + "name": "permutation", + "type": "mapAxis", + "mapAxis": { "x":"j", "y":"i" }, + "input": "in", + "output": "out2" + } + ] +} diff --git a/latest/examples/transformations/mapAxis2.json b/latest/examples/transformations/mapAxis2.json new file mode 100644 index 00000000..c8336aef --- /dev/null +++ b/latest/examples/transformations/mapAxis2.json @@ -0,0 +1,23 @@ +{ + "coordinateSystems": [ + { "name": "in", "axes": [ {"name": "a"}, {"name": "b"}]}, + { "name": "out_down", "axes": [ {"name": "x"}]}, + { "name": "out_up", "axes": [ {"name": "x"}, {"name": "y"}, {"name": "z"} ]} + ], + "coordinateTransformations": [ + { + "name": "projection down", + "type": "mapAxis", + "mapAxis": { "x": "b" }, + "input": "in", + "output": "out_down" + }, + { + "name": "projection up", + "type": "mapAxis", + "mapAxis": { "x": "a", "y": "b", "z": "b" }, + "input": "in", + "output": "out_up" + } + ] +} diff --git a/latest/examples/transformations/mapIndex1.json b/latest/examples/transformations/mapIndex1.json new file mode 100644 index 00000000..db785459 --- /dev/null +++ b/latest/examples/transformations/mapIndex1.json @@ -0,0 +1,23 @@ +{ + "coordinateSystems": [ + { "name": "in", "axes": [ {"name": "i"}, {"name": "j"} ]}, + { "name": "out1", "axes": [ {"name": "x"}, {"name": "y"} ]}, + { "name": "out2", "axes": [ {"name": "x"}, {"name": "y"} ]} + ], + "coordinateTransformations": [ + { + "name": "equivalent to identity", + "type": "mapIndex", + "mapIndex": [0, 1], + "input": "in", + "output": "out1" + }, + { + "name": "permutation", + "type": "mapIndex", + "mapIndex": [1, 0], + "input": "in", + "output": "out2" + } + ] +} diff --git a/latest/examples/transformations/mapIndex2.json b/latest/examples/transformations/mapIndex2.json new file mode 100644 index 00000000..411828de --- /dev/null +++ b/latest/examples/transformations/mapIndex2.json @@ -0,0 +1,23 @@ +{ + "coordinateSystems": [ + { "name": "in", "axes": [ {"name": "a"}, {"name": "b"}]}, + { "name": "out_down", "axes": [ {"name": "x"}]}, + { "name": "out_up", "axes": [ {"name": "x"}, {"name": "y"}, {"name": "z"} ]} + ], + "coordinateTransformations": [ + { + "name": "projection down", + "type": "mapIndex", + "mapIndex": [1], + "input": "in", + "output": "out_down" + }, + { + "name": "projection up", + "type": "mapIndex", + "mapIndex": [0, 1, 1], + "input": "in", + "output": "out_up" + } + ] +} diff --git a/latest/examples/transformations/rotation.json b/latest/examples/transformations/rotation.json new file mode 100644 index 00000000..5e73ff33 --- /dev/null +++ b/latest/examples/transformations/rotation.json @@ -0,0 +1,14 @@ +{ + "coordinateSystems" : [ + { "name" : "ij", "axes" : [{"name" : "i"}, {"name":"j"}] }, + { "name" : "xy", "axes" : [{"name" : "x"}, {"name":"y"}] } + ], + "coordinateTransformations" : [ + { + "type": "rotation", + "rotation": [0, -1, 1, 0], + "input" : "ij", + "output" : "xy" + } + ] +} \ No newline at end of file diff --git a/latest/examples/transformations/scale.json b/latest/examples/transformations/scale.json new file mode 100644 index 00000000..b5c83309 --- /dev/null +++ b/latest/examples/transformations/scale.json @@ -0,0 +1,14 @@ +{ + "coordinateSystems": [ + { "name": "in", "axes": [{"name": "i"}, {"name": "j"}] }, + { "name": "out", "axes": [{"name": "x"}, {"name": "y"}] } + ], + "coordinateTransformations": [ + { + "type": "scale", + "scale": [3.12, 2], + "input": "in", + "output": "out" + } + ] +} diff --git a/latest/examples/transformations/sequence.json b/latest/examples/transformations/sequence.json new file mode 100644 index 00000000..1d88b21d --- /dev/null +++ b/latest/examples/transformations/sequence.json @@ -0,0 +1,17 @@ +{ + "coordinateSystems": [ + { "name": "in", "axes": [ {"name": "i"}, {"name": "j"} ]}, + { "name": "out", "axes": [ {"name": "x"}, {"name": "y"} ]} + ], + "coordinateTransformations": [ + { + "type": "sequence", + "input": "in", + "output": "out", + "transformations": [ + { "type": "translation", "translation": [0.1, 0.9] }, + { "type": "scale", "scale": [2, 3] } + ] + } + ] +} diff --git a/latest/examples/transformations/sequenceSubspace1.json b/latest/examples/transformations/sequenceSubspace1.json new file mode 100644 index 00000000..e8a5bd35 --- /dev/null +++ b/latest/examples/transformations/sequenceSubspace1.json @@ -0,0 +1,17 @@ +{ + "coordinateSystems" : [ + { "name" : "in", "axes" : [ {"name" : "i"}, {"name" : "j"} ] }, + { "name" : "out", "axes" : [ {"name" : "x"}, {"name" : "y"} ] } + ], + "coordinateTransformations" : [ + { + "type" : "sequence", + "input" : "in", + "output" : "out", + "transformations" : [ + { "type" : "coordinates", "path" : "/coordinates", "inputAxes" : ["i"], "outputAxes" : ["x"]}, + { "type" : "scale", "scale" : [2.0], "inputAxes" : ["j"], "outputAxes" : ["y"]} + ] + } + ] +} diff --git a/latest/examples/transformations/translation.json b/latest/examples/transformations/translation.json new file mode 100644 index 00000000..cbc32ec9 --- /dev/null +++ b/latest/examples/transformations/translation.json @@ -0,0 +1,14 @@ +{ + "coordinateSystems": [ + { "name": "in", "axes": [{"name": "i"}, {"name": "j"}] }, + { "name": "out", "axes": [{"name": "x"}, {"name": "y"}] } + ], + "coordinateTransformations" : [ + { + "type": "translation", + "input": "in", + "output": "out", + "translation": [9, -1.42] + } + ] +} diff --git a/latest/examples/transformations/xarrayLike.json b/latest/examples/transformations/xarrayLike.json new file mode 100644 index 00000000..6a7c45b4 --- /dev/null +++ b/latest/examples/transformations/xarrayLike.json @@ -0,0 +1,17 @@ +{ + "coordinateSystems": [ + { "name": "in", "axes": [ {"name": "i", "type": "array"}, {"name": "j", "type": "array"} ]}, + { "name": "out", "axes": [ {"name": "x", "type": "space"}, {"name": "y", "type": "space"} ]} + ], + "coordinateTransformations": [ + { + "type": "byDimension", + "input": "in", + "output": "out", + "transformations": [ + { "type": "coordinates", "path": "/xCoordinates", "input" : ["i"], "output" : ["x"] }, + { "type": "coordinates", "path": "/yCoordinates", "input" : ["j"], "output" : ["y"] } + ] + } + ] +} diff --git a/latest/index.bs b/latest/index.bs index bb935c48..46ba6d6d 100644 --- a/latest/index.bs +++ b/latest/index.bs @@ -1,6 +1,6 @@
-Title: Next-generation file formats (NGFF) -Shortname: ome-ngff +Title: OME-Zarr specification +Shortname: ome-zarr Level: 1 Status: LS-COMMIT Status: w3c/ED @@ -16,6 +16,8 @@ Markup Shorthands: markdown yes Editor: Josh Moore, University of Dundee (UoD) https://www.dundee.ac.uk, https://orcid.org/0000-0003-4028-811X Editor: Sébastien Besson, University of Dundee (UoD) https://www.dundee.ac.uk, https://orcid.org/0000-0001-8783-1429 Editor: Constantin Pape, European Molecular Biology Laboratory (EMBL) https://www.embl.org/sites/heidelberg/, https://orcid.org/0000-0001-6562-7187 +Editor: John Bogovic, Hughes Medical Institute Janelia (HHMI) https://www.janelia.org/, https://orcid.org/0000-0002-4829-9457 +Editor: Norman Rzepka, scalable minds https://scalableminds.com/, https://orcid.org/0000-0002-8168-7929 Text Macro: NGFFVERSION 0.5-dev Abstract: This document contains next-generation file format (NGFF) Abstract: specifications for storing bioimaging data in the cloud. @@ -122,11 +124,13 @@ be stored on a web server to be accessed via HTTP or in object storage like S3 or GCS. OME-Zarr is an implementation of the OME-NGFF specification using the Zarr -format. Arrays MUST be defined and stored in a hierarchical organization as -defined by the -[version 2 of the Zarr specification ](https://zarr.readthedocs.io/en/stable/spec/v2.html). -OME-NGFF metadata MUST be stored as attributes in the corresponding Zarr -groups. +format. Arrays and groups MUST be defined and stored in a hierarchical organization as +defined by the [version 3 of the Zarr specification](https://zarr.readthedocs.io/en/stable/spec/v3.html). +OME metadata MUST be stored as attributes in the corresponding Zarr groups. + +All features of the Zarr format as finalized through the [ZEP process](https://zarr.dev/zeps/active/ZEP0000.html) are available in OME-Zarr. +This explicitly includes chunk key encodings, codecs, data types, and storage transformers. +Restrictions may be introduced in the future. Images {#image-layout} ---------------------- @@ -144,39 +148,45 @@ For this example we assume an image with 5 dimensions and axes called `t,c,z,y,x │ └── 456.zarr # Another image (id=456) converted to Zarr. │ - ├── .zgroup # Each image is a Zarr group, or a folder, of other groups and arrays. - ├── .zattrs # Group level attributes are stored in the .zattrs file and include - │ # "multiscales" and "omero" (see below). In addition, the group level attributes - │ # must also contain "_ARRAY_DIMENSIONS" if this group directly contains multi-scale arrays. + ├── zarr.json # Each image is a Zarr group, or a folder, of other groups and arrays. + │ # Group level attributes are stored in the zarr.json file and include + │ # "multiscales" and "omero" (see below). │ ├── 0 # Each multiscale level is stored as a separate Zarr array, │ ... # which is a folder containing chunk files which compose the array. ├── n # The name of the array is arbitrary with the ordering defined by │ │ # by the "multiscales" metadata, but is often a sequence starting at 0. │ │ - │ ├── .zarray # All image arrays must be up to 5-dimensional + │ ├── zarr.json # All image arrays must be up to 5-dimensional │ │ # with the axis of type time before type channel, before spatial axes. │ │ - │ └─ t # Chunks are stored with the nested directory layout. - │ └─ c # All but the last chunk element are stored as directories. - │ └─ z # The terminal chunk is a file. Together the directory and file names - │ └─ y # provide the "chunk coordinate" (t, c, z, y, x), where the maximum coordinate - │ └─ x # will be `dimension_size / chunk_size`. + │ └─ c # Chunks are stored with the chunk key encoding as specified in the zarr.json. + | | # In this example, the chunk key encoding is "default" with separator "/". + | | # The chunk keys (composed of file path and file name) provide the "chunk coordinate" (t, c, z, y, x). + │ ├─ 0 # Time dimension + | | ├─ 0 # Channel dimension + | | | ├─ 0 # Z dimension + | | | | ├─ 0 # Y dimension + | | | | | ├─ 0 # X dimension + | | | | | └─ ... + | | | | └─ ... + | | | └─ ... + | | └─ ... + │ └─ ... │ └── labels │ - ├── .zgroup # The labels group is a container which holds a list of labels to make the objects easily discoverable - │ - ├── .zattrs # All labels will be listed in `.zattrs` e.g. `{ "labels": [ "original/0" ] }` + ├── zarr.json # The labels group is a container which holds one or more multiscale labels. + │ # All labels will be listed in the top-level attributes e.g. `{ "labels": [ "labels/original/0" ] }` │ # Each dimension of the label `(t, c, z, y, x)` should be either the same as the │ # corresponding dimension of the image, or `1` if that dimension of the label │ # is irrelevant. │ └── original # Intermediate folders are permitted but not necessary and currently contain no extra metadata. │ - └── 0 # Multiscale, labeled image. The name is unimportant but is registered in the "labels" group above. - ├── .zgroup # Zarr Group which is both a multiscaled image as well as a labeled image. - ├── .zattrs # Metadata of the related image and as well as display information under the "image-label" key. + └── 0 # Multiscale, labeled image. The name is unimportant but is registered in the "labels" metadata above. + ├── zarr.json # Zarr Group which is both a multiscaled image as well as a labeled image including + │ # metadata of the related image and as well as display information under the "image-label" key. │ ├── 0 # Each multiscale level is stored as a separate Zarr array, as above, but only integer values │ ... # are supported. @@ -189,7 +199,7 @@ High-content screening {#hcs-layout} ------------------------------------ The following specification defines the hierarchy for a high-content screening -dataset. Three groups MUST be defined above the images: +dataset. Three groups must be defined above the images: - the group above the images defines the well and MUST implement the [well specification](#well-md). All images contained in a well are fields @@ -199,27 +209,21 @@ dataset. Three groups MUST be defined above the images: collection of wells organized in rows and columns. It MUST implement the [plate specification](#plate-md) -A well row group SHOULD NOT be present if there are no images in the well row. -A well group SHOULD NOT be present if there are no images in the well. -. # Root folder, potentially in S3, │ └── 5966.zarr # One plate (id=5966) converted to Zarr - ├── .zgroup - ├── .zattrs # Implements "plate" specification + ├── zarr.json # Implements "plate" specification ├── A # First row of the plate - │ ├── .zgroup + │ ├── zarr.json │ │ │ ├── 1 # First column of row A - │ │ ├── .zgroup - │ │ ├── .zattrs # Implements "well" specification + │ │ ├── zarr.json # Implements "well" specification │ │ │ │ │ ├── 0 # First field of view of well A1 │ │ │ │ - │ │ │ ├── .zgroup - │ │ │ ├── .zattrs # Implements "multiscales", "omero" + │ │ │ ├── zarr.json # Implements "multiscales", "omero" │ │ │ ├── 0 │ │ │ │ ... # Resolution levels │ │ │ ├── n @@ -235,20 +239,25 @@ A well group SHOULD NOT be present if there are no images in the well. Metadata {#metadata} ==================== -The various `.zattrs` files throughout the above array hierarchy may contain metadata +The various `zarr.json` files throughout the above array hierarchy may contain OME metadata keys as specified below for discovering certain types of data, especially images. +All OME metadata is stored under a `ome` key within the `attributes` of these `zarr.json` files. -"axes" metadata {#axes-md} --------------------------- +-"axes" describes the dimensions of a physical coordinate space. It is a list of dictionaries, where each dictionary describes a dimension (axis) and: -- MUST contain the field "name" that gives the name for this dimension. The values MUST be unique across all "name" fields. -- SHOULD contain the field "type". It SHOULD be one of "space", "time" or "channel", but MAY take other values for custom axis types that are not part of this specification yet. -- SHOULD contain the field "unit" to specify the physical unit of this dimension. The value SHOULD be one of the following strings, which are valid units according to UDUNITS-2. - - Units for "space" axes: 'angstrom', 'attometer', 'centimeter', 'decimeter', 'exameter', 'femtometer', 'foot', 'gigameter', 'hectometer', 'inch', 'kilometer', 'megameter', 'meter', 'micrometer', 'mile', 'millimeter', 'nanometer', 'parsec', 'petameter', 'picometer', 'terameter', 'yard', 'yoctometer', 'yottameter', 'zeptometer', 'zettameter' - - Units for "time" axes: 'attosecond', 'centisecond', 'day', 'decisecond', 'exasecond', 'femtosecond', 'gigasecond', 'hectosecond', 'hour', 'kilosecond', 'megasecond', 'microsecond', 'millisecond', 'minute', 'nanosecond', 'petasecond', 'picosecond', 'second', 'terasecond', 'yoctosecond', 'yottasecond', 'zeptosecond', 'zettasecond' - -If part of [[#multiscale-md]], the length of "axes" MUST be equal to the number of dimensions of the arrays that contain the image data. +```json +{ + "zarr_format": 3, + "node_type": "group", + "attributes": { + "ome": { + "version": "0.5-dev", + ... + } + } +} +``` +"bioformats2raw.layout" (transitional) {#bf2raw} ------------------------------------------------ @@ -267,11 +276,9 @@ Typical Zarr layout produced by running `bioformats2raw` on a fileset that contaseries.ome.zarr # One converted fileset from bioformats2raw - ├── .zgroup - ├── .zattrs # Contains "bioformats2raw.layout" metadata + ├── zarr.json # Contains "bioformats2raw.layout" metadata ├── OME # Special group for containing OME metadata - │ ├── .zgroup - │ ├── .zattrs # Contains "series" metadata + │ ├── zarr.json # Contains "series" metadata │ └── METADATA.ome.xml # OME-XML file stored within the Zarr fileset ├── 0 # First image in the collection ├── 1 # Second image in the collection @@ -280,7 +287,7 @@ series.ome.zarr # One converted fileset from bioformats2rawAttributes
-The top-level `.zattrs` file must contain the `bioformats2raw.layout` key: +The top-level OME group attributes must contain the `bioformats2raw.layout` key:path: examples/bf2raw/image.json highlight: json @@ -295,7 +302,7 @@ path: examples/bf2raw/plate.json highlight: json-The `.zattrs` file within the OME group may contain the "series" key: +The attributes within the OME group may contain the "series" key:path: examples/ome/series-2.json @@ -306,7 +313,7 @@ highlight: json Conforming groups: -- MUST have the value "3" for the "bioformats2raw.layout" key in their `.zattrs` metadata at the top of the hierarchy; +- MUST have the value "3" for the "bioformats2raw.layout" key in their OME attribute metadata at the top of the hierarchy; - SHOULD have OME metadata representing the entire collection of images in a file named "OME/METADATA.ome.xml" which: - MUST adhere to the OME-XML specification but - MUST use `` elements as opposed to ` `, ` ` or ` `; @@ -331,24 +338,1010 @@ Conforming readers: - MAY ignore other groups or arrays under the root of the hierarchy. +"coordinateSystems" metadata {#coord-sys-md} +-------------------------- + +A "coordinate system" is a collection of "axes" / dimensions with a name. Every coordinate system: +- MUST contain the field "name". The value MUST be a non-empty string that is unique among `coordinateSystem`s. +- MUST contain the field "axes", whose value is an array of valid "axes" (see below). + + + +```json +{ + "name" : "volume_micrometers", + "axes" : [ + {"name": "x", "type": "space", "unit": "micrometer"}, + {"name": "y", "type": "space", "unit": "micrometer"}, + {"name": "z", "type": "space", "unit": "micrometer"} + ] +} +``` ++ +The order of the `"axes"` list matters and defines the index of each array dimension and coordinates for points in that +coordinate system. For the above example, the `"x"` dimension is the first dimension. The "dimensionality" of a coordinate system +is indicated by the length of its "axes" array. The "volume_micrometers" example coordinate system above is three dimensional (3D). + +The axes of a coordinate system (see below) give information about the types, units, and other properties of the coordinate +system's dimensions. Axis `name`s may contain semantically meaningful information, but can be arbitrary. As a result, two +coordinate systems that have identical axes in the same order may not be "the same" in the sense that measurements at the same +point refer to different physical entities and therefore should not be analyzed jointly. Task that require images, annotations, +regions of interest, etc. SHOULD ensure that they are in the same coordinate system (same name, with identical axes) or can be +transformed to the same coordinate system before doing analysis. See the example below. + ++ +Two instruments simultaneously image the same sample from two different angles, and the 3D data from both instruments are +calibrated to "micrometer" units. Two samples are collected ("sampleA" and "sampleB"). An analysis of sample A requires +measurements from both instruments' images at certain points in space. Suppose a region of interest (ROI) is determined from the +image obtained from instrument 2, but quantification from that region is needed for instrument 1. Since measurements were +collected at different angles, a measurement by instrument 1 at the point with coordinates (x,y,z) may not correspond to the +measurement at the same point in instrument 2 (i.e., it may not be the same physical location in the sample). To analyze both +images together, they must be in the same coordinate system. + +The set of coordinate transformations ([[#trafo-md]]) encodes relationships between coordinate systems, specifically, how to +convert points and images to different coordinate systems. Implementations can apply the coordinate transform to images or +points in coordinate system "sampleA_instrument2" to bring them into the "sampleA_instrument1" coordinate system. In this case, +the ROI should be transformed to the "sampleA_image1" coordinate system, then used for quantification with the instrument 1 +image. + +```json +"coordinateSystems" : [ + { + "name" : "sampleA-instrument1", + "axes" : [ + {"name": "x", "type": "space", "unit": "micrometer"}, + {"name": "y", "type": "space", "unit": "micrometer"}, + {"name": "z", "type": "space", "unit": "micrometer"} + ] + }, + { + "name" : "sampleA-instrument2", + "axes" : [ + {"name": "x", "type": "space", "unit": "micrometer"}, + {"name": "y", "type": "space", "unit": "micrometer"}, + {"name": "z", "type": "space", "unit": "micrometer"} + ] + } +], +"coordinateTransformations": [ + { + "type": "affine": + "path": "../sampleA_instrument2-to-instrument1" + "input": "sampleA_instrument2", + "output": "sampleA_instrument1" + } +] +``` + ++ + + +### "axes" metadata {#axes-md} + +"axes" describes the dimensions of a coordinate systems. It is a list of dictionaries, where each dictionary describes a dimension (axis) and: +- MUST contain the field "name" that gives the name for this dimension. The values MUST be unique across all "name" fields. +- SHOULD contain the field "type". It SHOULD be one of "array", "space", "time", "channel", "coordinate", or "displacement" but MAY take other values for custom axis types that are not part of this specification yet. +- MAY contain the field "discrete". The value MUST be a boolean, and is `true` if the axis represents a discrete dimension. +- SHOULD contain the field "unit" to specify the physical unit of this dimension. The value SHOULD be one of the following strings, which are valid units according to UDUNITS-2. + - Units for "space" axes: 'angstrom', 'attometer', 'centimeter', 'decimeter', 'exameter', 'femtometer', 'foot', 'gigameter', 'hectometer', 'inch', 'kilometer', 'megameter', 'meter', 'micrometer', 'mile', 'millimeter', 'nanometer', 'parsec', 'petameter', 'picometer', 'terameter', 'yard', 'yoctometer', 'yottameter', 'zeptometer', 'zettameter' + - Units for "time" axes: 'attosecond', 'centisecond', 'day', 'decisecond', 'exasecond', 'femtosecond', 'gigasecond', 'hectosecond', 'hour', 'kilosecond', 'megasecond', 'microsecond', 'millisecond', 'minute', 'nanosecond', 'petasecond', 'picosecond', 'second', 'terasecond', 'yoctosecond', 'yottasecond', 'zeptosecond', 'zettasecond' +- MAY contain the field "longName". The value MUST be a string, and can provide a longer name or description of an axis and its properties. + +If part of [[#multiscale-md]], the length of "axes" MUST be equal to the number of dimensions of the arrays that contain the image data. + ++ +Examples of valid axes: + +```json +[ + {"name": "x", "type": "space", "unit": "micrometer"}, + {"name": "t", "type": "time", "unit": "second", "longName": "Unix Epoch time"}, + {"name": "c", "type": "channel", "discrete": true}, + {"name": "i0", "type": "array"}, + {"name": "c", "type": "coordinate", "discrete" : true }, + {"name": "v", "type": "displacement", "discrete": true }, + {"name": "freq", "type": "frequency", "unit": "megahertz"} +] +``` ++ +Arrays are often thought of as containing discrete samples along the continuous variable. Axes representing space and time are +usually continuous, meaning they can be indexed by real-valued (floating point) numbers whereas discrete axes may be indexed +only by integers. Arrays are inherently discrete (see Array coordinate systems, below) , but values "in between" discrete +coordinates can be retreived using an *interpolation* method. If an axis is continuous (`"discrete" : false`), it indicates +that indexing with continuous values is meaningful, and that interpolation may be performed along that axis. Interpolation may +be performed jointly across axes with the same `type`, and interpolation should not be performed for discrete axes or jointly +across axes with differing `type`s. Other non-continuous variables and axis types are also usually discrete, such as +`channel`s, `coordinate`s, and `displacement`s. + +Note: The most common methods for interpolation are "nearest neighbor", "linear", "cubic", and "windowed sinc". Here, we refer +to any method that obtains values at real valued coordinates using discrete samples as an "interpolator". As such, label images +may be interpolated using "nearest neighbor" to obtain labels at points along the continuum. + ++ +For the coordinate system: + +```json +{ + "name" : "index and interpolation", + "axes" : [ + {"name": "c", "type": "channel", "discrete": true}, + {"name": "x", "type": "space"}, + {"name": "y", "type": "space"}, + {"name": "t", "type": "time"}, + ] +} +``` + +Indexing an image at the point `(0.1, 0.2, 0.3, 0.4)` is not valid, because the value of the first coordinate (`0.1`) refers +to the discrete axis `"c"`. Indexing an image at the point `(1, 0.2, 0.3, 0.4)` is valid. ++ +The axes names of an array MAY be duplicated in the Zarr metadata key `dimension_names`. +Implementations MUST give precedence to the `axes` metadata over the `dimenions_names`. + + +### Array coordinate systems + +Every array has a default coordinate system whose parameters need not be explicitly defined. Its name is the path to the array +in the container, its axes have `"type":"array"`, are unitless, and have default "name"s. The ith axis has `"name":"dim_i"` +(these are the same default names used by [xarray](https://docs.xarray.dev/en/stable/user-guide/terminology.html)). ++For example, a 3D array at path `/my/data/array` defines the coordinate system: + +```json +{ + "name" : "/my/data/array", + "axes" : [ + {"name": "dim_0", "type": "array"}, + {"name": "dim_1", "type": "array"}, + {"name": "dim_2", "type": "array"} + ] +} +``` + +though this object should not and need not explicitly appear in metadata. ++ + +The dimensionality of each array coordinate system equals the dimensionality of its corresponding zarr array. The axis with +name `"dim_i"` is the ith element of the `"axes"` list. The axes and their order align with the `shape` +attribute in the zarr array attributes (in `zarr.json`), and whose data depends on the byte order used to store +chunks. As described in the [zarr array metadata](https://zarr.readthedocs.io/en/stable/spec/v2.html#arrays), +the last dimension of an array in "C" order (row-major) are stored contiguously. For an array in "F" +(column-major) order, the elements of the first dimension are stored contiguously. + ++For example, if `/my/data/array/zarr.json` contains: + +```json +{ + "zarr_format": 3 + "data_type": "uint8", + "fill_value": 0, + "shape": [ 4, 3, 5 ], + "chunk_grid": { + "name": "regular", + "configuration": { + "chunk_shape": [ 4, 3, 5 ] + } + }, + "codecs": [ + { + "name": "endian", + "configuration": { "endian": "little" } + } + ] +} +``` + +Then `dim_0` has length 4, `dim_1` has length 3, and `dim_2` has length 5. ++ +The name and axes names MAY be customized by including a `arrayCoordinateSystem` field in +the OME attributes of the array whose value is a coordinate system object. The length of +`axes` MUST be equal to the dimensionality. The value of `"type"` for each object in the +axes array MUST equal `"array"`. + ++ ++ + +### Coordinate convention + +**The pixel/voxel center is the origin of the continuous coordinate system.** + +It is vital to consistently define relationship between the discrete/array and continuous/interpolated +coordinate systems. A pixel/voxel is the continuous region (rectangle) that corresponds to a single sample +in the discrete array, i.e., the area corresponding to nearest-neighbor (NN) interpolation of that sample. +The center of a 2d pixel corresponding to the origin `(0,0)` in the discrete array is the origin of the continuous coordinate +system `(0.0, 0.0)` (when the transformation is the identity). The continuous rectangle of the pixel is given by the +half-open interval `[-0.5, 0.5) x [-0.5, 0.5)` (i.e., -0.5 is included, +0.5 is excluded). See chapter 4 and figure 4.1 of the ITK Software Guide [[itk]]. +======= + + + "coordinateTransformations" metadata {#trafo-md} ------------------------------------------------ -"coordinateTransformations" describe a series of transformations that map between two coordinate spaces (defined by "axes"). -For example, to map a discrete data space of an array to the corresponding physical space. -It is a list of dictionaries. Each entry describes a single transformation and MUST contain the field "type". -The value of "type" MUST be one of the elements of the `type` column in the table below. -Additional fields for the entry depend on "type" and are defined by the column `fields`. +"coordinateTransformations" describe the mapping between two coordinate systems (defined by "axes"). +For example, to map an array's discrete coordinate system to its corresponding physical coordinates. +Coordinate transforms are in the "forward" direction. They represent functions from *points* in the +input space to *points* in the output space. + + +- MUST contain the field "type". +- MUST contain any other fields required by the given "type" (see table below). +- MUST contain the field "output", unless part of a `sequence` or `inverseOf` (see details). +- MUST contain the field "input", unless part of a `sequence` or `inverseOf` (see details). +- MAY contain the field "name". Its value MUST be unique across all "name" fields for coordinate transformations. +- Parameter values MUST be compatible with input and output space dimensionality (see details).+path: examples/coordSystems/arrayCoordSys.json +highlight: json ++ +
`identity` | identity transformation, is the default transformation and is typically not explicitly defined - | ||||
---|---|---|---|---|---|
`translation` | one of: `"translation":List[float]`, `"path":str` | translation vector, stored either as a list of floats (`"translation"`) or as binary data at a location in this container (`path`). The length of vector defines number of dimensions. | - | |||
`scale` | one of: `"scale":List[float]`, `"path":str` | scale vector, stored either as a list of floats (`scale`) or as binary data at a location in this container (`path`). The length of vector defines number of dimensions. | + | |||
`identity` + | + | The identity transformation is the default transformation and is typically not explicitly defined. + | |||
`mapIndex` + | `"mapIndex":List[number]` + | A `mapIndex` transformation specifies an axis permutation by reordering the input axes. + | |||
`mapAxis` + | `"mapAxis":Dict[String:String]` + | A `maxAxis` transformation specifies an axis permutation as a map between axis names. + | |||
`translation` + | one of: `"translation":List[number]`, `"path":str` + | translation vector, stored either as a list of numbers (`"translation"`) or as binary data at a location + in this container (`path`). + | |||
`scale` + | one of: `"scale":List[number]`, `"path":str` + | scale vector, stored either as a list of numbers (`scale`) or as binary data at a location in this + container (`path`). + | |||
`affine` + | one of: `"affine":List[number]`, `"path":str` + | affine transformation matrix stored as a flat array stored either with json uing the affine field + or as binary data at a location in this container (path). If both are present, the binary values at path should be used. + | |||
`rotation` + | one of: `"rotation":List[number]`, `"path":str` + | rotation transformation matrix stored as an array stored either + with json or as binary data at a location in this container (path). + If both are present, the binary parameters at path are used. + | |||
`sequence` + | `"transformations":List[Transformation]` + | A sequence of transformations, Applying the sequence applies the composition of all transforms in the list, in order. + | |||
`displacements` + | `"path":str` `"interpolation":str` + | Displacement field transformation located at (path). + | |||
`coordinates` + | `"path":str` `"interpolation":str` + | Coordinate field transformation located at (path). + | |||
`inverseOf` + | `"transform":Transform` + | The inverse of a transformation. Useful if a transform is not closed-form invertible. See Forward and inverse for details and examples. + | |||
`bijection` + | `"forward":Transform` `"inverse":Transform` + | Explicitly define an invertible transformation by providing a forward transformation and its inverse. + | |||
`byDimension` + | `"transformations":List[Transformation]` + | Define a high dimensional transformation using lower dimensional transformations on subsets of
+ dimensions.
type | fields | description
| |
+store.zarr # Root folder of the zarr store +│ +├── zarr.json # coordinate transformations describing the relationship between two image coordinate systems +│ # are stored in the attributes of their parent group. +│ # transformations between 'volume' and 'crop' coordinate systems are stored here. +│ +├── coordinateTransformations # transformations that use array storage go in a "transformations" zarr group. +│ └── displacements # for example, a zarray containing a displacement field +│ └── zarr.json +│ +├── volume +│ ├── zarr.json # group level attributes (multiscales) +│ └── 0 # a group containing the 0th scale +│ └── image # a zarr array +│ └── zarr.json # physical coordinate system and transformations here the array attributes +└── crop + ├── zarr.json # group level attributes (multiscales) + └── 0 # a group containing the 0th scale + └── image # a zarr array + └── zarr.json # physical coordinate system and transformations here the array attributes ++ +### Additional details + +Most coordinate transformations MUST specify their input and output coordinate systems using `input` and `output` with a string value +corresponding to the name of a coordinate system. The coordinate system's name may be the path to an array, and therefore may +not appear in the list of coordinate systems. + +Exceptions are if the the coordinate transformation appears in the `transformations` list of a `sequence` or is the +`transformation` of an `inverseOf` transformation. In these two cases input and output SHOULD be omitted (see below for +details). + +Transformations in the `transformations` list of a `byDimensions` transforemation MUST provide `input` and `output` as arrays +of strings corresponding to axis names of the parent transformation's input and output coordinate systems (see below for +details). + +
+path: examples/transformations/identity.json +highlight: json ++ +defines the function: + +``` +x = i +y = j +``` + +
+path: examples/transformations/mapIndex1.json +highlight: json ++ +The "equivalent to identity" transformation defines the function: + +``` +x = i +y = j +``` + +and the "permutation" transformation defines the function + +``` +x = j +y = i +``` + +
+path: examples/transformations/mapIndex2.json +highlight: json ++ +The "projection_down" transformation defines the function: + +``` +x = b +``` + +and the "projection_up" transformation defines the function: + +``` +x = a +y = b +z = b +``` + +
+path: examples/transformations/mapAxis1.json +highlight: json ++ +The "equivalent to identity" transformation defines the function: + +``` +x = i +y = j +``` + +and the "permutation" transformation defines the function + +``` +x = j +y = i +``` + +
+path: examples/transformations/mapAxis2.json +highlight: json ++ +The "projection_down" transformation defines the function: + +``` +x = b +``` + +and the "projection_up" transformation defines the function: + +``` +x = a +y = b +z = b +``` +
+path: examples/transformations/translation.json +highlight: json ++ +defines the function: + +``` +x = i + 9 +y = j - 1.42 +``` +
+path: examples/transformations/scale.json +highlight: json ++ +defines the function: + +``` +x = 3.12 * i +y = 2 * j +``` +
+ path: examples/transformations/affine2d2d.json + highlight: json ++ + defines the function: + + ``` + x = 1*i + 2*j + 3 + y = 4*i + 5*j + 6 + ``` +
+ path: examples/transformations/affine2d3d.json + highlight: json ++ + defines the function: + + ``` + x = 1*i + 2*j + 3 + y = 4*i + 5*j + 6 + z = 7*i + 8*j + 9 + ``` + + Using a nested 2D JSON array, the same transformation can be written: +
+ path: examples/transformations/affine2d3d_nested.json + highlight: json ++ +
+ path: examples/transformations/rotation.json + highlight: json ++ + defines the function: + + ``` + x = 0*i - 1*j + y = 1*i + 0*j + ``` +
+ path: examples/transformations/inverseOf.json + highlight: json ++ +
+path: examples/transformations/sequence.json +highlight: json ++ +describes the function + +``` +x = (i + 0.1) * 2 +y = (j + 0.9) * 3 +``` + +and is invertible. +
linear
(default)nearest
cubic
+path: examples/transformations/byDimension1.json +highlight: json ++ +
+path: examples/transformations/byDimension2.json +highlight: json ++ +
+path: examples/transformations/byDimensionInvalid1.json +highlight: json ++ +It is invalid for two reasons. First because input `0` used by the scale transformation is not an axis of the `byDimension` transformation's `input`. Second, the `x` axis of the `output` does not appear in the `output` of any child transformation. + +
+path: examples/transformations/byDimensionInvalid2.json +highlight: json ++ +This transformation is invalid because the output axis `x` appears in more than one transformation in the `transformations` list. + +
+path: examples/transformations/bijection.json +highlight: json ++ +the input and output of the `forward` and `inverse` transformations are understoood to be: + +
+path: examples/transformations/bijection_verbose.json +highlight: json ++ +
+Title: Coordinates and Transformations +Shortname: ome-ngff-transformations +Level: 1 +Status: LS-COMMIT +Status: w3c/ED +Group: ome +URL: https://ngff.openmicroscopy.org/latest/ +Repository: https://github.com/ome/ngff +Issue Tracking: Forums https://forum.image.sc/tag/ome-ngff +Logo: http://www.openmicroscopy.org/img/logos/ome-logomark.svg +Local Boilerplate: header no +Local Boilerplate: copyright no +Boilerplate: style-darkmode off +Markup Shorthands: markdown yes +Editor: Josh Moore, Open Microscopy Environment (OME) https://www.openmicroscopy.org +Editor: Sébastien Besson, Open Microscopy Environment (OME) https://www.openmicroscopy.org +Editor: Constantin Pape, European Molecular Biology Laboratory (EMBL) https://www.embl.org/sites/heidelberg/ +Editor: John Bogovic, Hughes Medical Institute Janelia (HHMI) https://www.janelia.org/ +Editor: Norman Rzepka, scalable minds https://scalableminds.com/, https://orcid.org/0000-0002-8168-7929 +Abstract: This document contains next-generation file format (NGFF) +Abstract: specifications for storing bioimaging data in the cloud. +Abstract: All specifications are submitted to the https://image.sc community for review. +Status Text: The current released version of this specification is +Status Text: will be provided between numbered versions. Data written with these latest changes +Status Text: (an "editor's draft") will not necessarily be supported. ++ +Coordinates and Axes {#coords-axes} +===================== + +OME-Zarr datasets are arrays that hold values. The arrays may be indexed by discrete (integer) +coordinates in order to obtain a corresponding value. If values are desired at continuous (real-valued) +coordinates, then interpolation is required. + +Interpolation {#interp} +--------------------- + +Interpolation is the process of producing values at continuous coordinates from data sampled at discrete +coordinates. "Nearest-neighbor" and "N-Linear" are the two most commonly used interpolation methods. + + +Pixel coordinates {#pix-coords} +--------------------- + +**The pixel center is the origin of the continuous coordinate system.** + +### Top-left convention + +A common alternative convention is for the origin in the continuous space is at the "top-left" of the pixel. +This is not recommended, but can be acheived by explicitly adding a half-pixel translation, for example: + +```json +{ + "name": "center_to_top-left", + "type": "translation", + "translation" : [0.5, 0.5], + "output_space" : "top-left-space" +} +``` + +Coordinate Transformations {#coord-tforms} +===================== + +This document describes background and motivation that is outside the NGFF specification. + + +Direction {#direction} +--------------------- + +Specified coordinate transforms are in the "forward" direction. They represent functions +from *points* in the input space to *points* in the output space. For example, the transformation `"ij2xy"` + + +```json +{ + "name": "ij2xy", + "type": "scale", + "scale": [2, 0.5] + "input_axes" : ["i", "j"] + "output_axes" : ["x", "y"] +} +``` + +representes the function + +``` +x = 2 * i +y = 0.5 * j +``` + + +Recommendations {#recommendations} +===================== + + +"Native" physical space +--------------------- + +Datasets SHOULD define a transformation from array space to their "native physical space." +This transformation SHOULD describe physical pixel spacing and origin only, and therefore SHOULD consist of +`scale` and/or `translation` types only. + +Subsequent reorientation / registration transformations SHOULD use this native space as their `input_space`, +i.e., transformations should be defined in physical coordinates. + +