Skip to content

Commit 171bb3c

Browse files
committed
Merge remote-tracking branch 'upstream/main' into unify-input-output
2 parents 01ffea8 + 29d6a9d commit 171bb3c

1 file changed

Lines changed: 130 additions & 64 deletions

File tree

index.md

Lines changed: 130 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -280,74 +280,33 @@ Here, we refer to any method that obtains values at real-valued coordinates usin
280280
As such, label images may be interpolated using "nearest neighbor" to obtain labels at points along the continuum.
281281
```
282282

283-
#### Array coordinate systems
284-
285-
The dimensions of an array do not have an interpretation
286-
until they are associated with a coordinate system via a coordinate transformation.
287-
Nevertheless, it can be useful to refer to the "raw" coordinates of the array.
288-
Some applications might prefer to define points or regions-of-interest in "pixel coordinates" rather than "physical coordinates," for example.
289-
Indicating that choice explicitly will be important for interoperability.
290-
This is possible by using **array coordinate systems**.
291-
292-
Every array has a default coordinate system whose parameters need not be explicitly defined.
293-
The dimensionality of each array coordinate system equals the dimensionality of its corresponding Zarr array.
294-
Its name is the path to the array in the container,
295-
its axes have `"type": "array"`, are unitless, and have default names.
296-
The i-th axis has `"name": "dim_i"` (these are the same default names used by [xarray](https://docs.xarray.dev/en/stable/user-guide/terminology.html)).
297-
As with all coordinate systems, the dimension names must be unique and non-null.
298-
299-
:::{dropdown} Example
300-
```json
301-
{
302-
"arrayCoordinateSystem" : {
303-
"name" : "myDataArray",
304-
"axes" : [
305-
{"name": "dim_0", "type": "array"},
306-
{"name": "dim_1", "type": "array"},
307-
{"name": "dim_2", "type": "array"}
308-
]
309-
}
310-
}
311-
312-
```
313-
314-
For example, if 0/zarr.json contains:
315-
```json
316-
{
317-
"zarr_format": 3,
318-
"node_type": "array",
319-
"shape": [4, 3, 5],
320-
//...
321-
}
322-
```
323-
324-
Then `dim_0` has length 4, `dim_1` has length 3, and `dim_2` has length 5.
325-
326-
:::
327-
328-
The axes and their order align with the shape of the corresponding Zarr array,
329-
and whose data depends on the byte order used to store chunks.
330-
As described in the [Zarr array metadata](https://zarr.readthedocs.io/en/stable/spec/v3.html#arrays),
331-
the last dimension of an array in "C" order are stored contiguously on disk or in-memory when directly loaded.
332-
333-
The name and axes names MAY be customized by including a `arrayCoordinateSystem` field
334-
in the user-defined attributes of the array whose value is a coordinate system object.
335-
The length of `axes` MUST be equal to the dimensionality.
336-
The value of `type` for each object in the axes array MUST equal `"array"`.
337-
338283
#### Coordinate convention
339284

340285
**The pixel/voxel center is the origin of the continuous coordinate system.**
341286

342-
It is vital to consistently define relationship
343-
between the discrete/array and continuous/interpolated coordinate systems.
344-
A pixel/voxel is the continuous region (rectangle) that corresponds to a single sample in the discrete array, i.e.,
345-
the area corresponding to nearest-neighbor (NN) interpolation of that sample.
346-
The center of a 2d pixel corresponding to the origin `(0,0)` in the discrete array
347-
is the origin of the continuous coordinate system `(0.0, 0.0)` (when the transformation is the identity).
348-
The continuous rectangle of the pixel is given
349-
by the half-open interval `[-0.5, 0.5) x [-0.5, 0.5)` (i.e., -0.5 is included, +0.5 is excluded).
350-
See chapter 4 and figure 4.1 of the ITK Software Guide.
287+
It is vital to consistently define relationship between the discrete/array and continuous/interpolated coordinate systems.
288+
The following conventions apply in this specification:
289+
290+
- The discrete coordinate grid for a Zarr array of shape `[N₀, N₁, ..., Nₖ]`
291+
is defined as zero-based, with indices ranging from 0 to Nᵢ - 1 for each dimension i.
292+
For example, given an array with shape (2, 3),
293+
the discrete coordinate system for that array defines the following array of points:
294+
```
295+
[
296+
[(0, 0), (0, 1)],
297+
[(1, 0), (1, 1)],
298+
[(2, 0), (3, 1)],
299+
]
300+
```
301+
- A "pixel"/"voxel" is the continuous region (rectangle/box) that corresponds to a single sample in the discrete array,
302+
i.e., the area corresponding to nearest-neighbor (NN) interpolation of that sample.
303+
- The center of a 2d pixel corresponding to the origin (0,0) in the discrete array
304+
is the origin of the continuous coordinate system (0.0, 0.0) (when the transformation is the identity).
305+
- The continuous rectangle of the pixel is given
306+
by the half-open interval [-0.5, 0.5) x [-0.5, 0.5) (i.e., -0.5 is included, +0.5 is excluded).
307+
308+
For a more formal and in-depth definition,
309+
see chapter 4 and figure 4.1 of the [ITK Software Guide](https://itk.org/ItkSoftwareGuide.pdf).
351310

352311
### bioformats2raw.layout
353312

@@ -620,6 +579,113 @@ to do so by estimating the transformations' inverse if they choose to.
620579
```
621580
:::
622581

582+
**Transformations in array coordinate units**:
583+
Some applications might prefer to define points, regions-of-interest or transformation parameters
584+
in array coordinates (also referred to as pixel coordinates) rather than physical units.
585+
Because transformations are agnostic to whether they operate on array or physical coordinates,
586+
indicating that choice explicitly will be important for interoperability.
587+
This can be expressed in the metadata in multiple ways, including:
588+
- One can embed a transformation defined in array units into a `sequence` transformation
589+
that includes the appropriate scale transformation and its inverse to convert to physical units (see example below).
590+
- One can define a unitless coordinate system and connect it to the "intrinsic" coordinate system
591+
with a scale transformation that has the appropriate scale factors to convert to physical units.
592+
593+
:::{dropdown} Example: Embedded expression
594+
595+
In the context of [`scene`](#scene-md), one may want to express a transformation between two images in dimensionless units,
596+
even though the coordinate systems of the two images are in physical units.
597+
This can be achieved by embedding the transformation into a `sequence` transformation like this:
598+
599+
```json
600+
{ "scene":
601+
{
602+
"type": "sequence",
603+
"input": {"name": "intrinsic", "path": "imageA"},
604+
"output": {"name": "intrinsic", "path": "imageB"},
605+
"transformations": [
606+
{
607+
"type": "scale",
608+
"scale": [2, 2],
609+
},
610+
{
611+
"type": "translation",
612+
"translation": [10, 20],
613+
"name": "translation in dimensionless units"
614+
},
615+
{
616+
"type": "scale",
617+
"scale": [0.5, 0.5],
618+
}
619+
]
620+
}
621+
}
622+
```
623+
624+
This example assumes that the coordinate system named `"intrinsic"` in both referenced images is in physical units,
625+
and is linked to the lowest resolution level (e.g., `s0`) of the multiscale image with a `scale` transformation that has the scale factors `[0.5, 0.5]`.
626+
In this case, the the first `scale` transformation in this example converts the input coordinates from physical to dimensionless units.
627+
The `translation` transformation is applied in dimensionless units,
628+
and finally the second `scale` transformation converts the coordinates back to physical units.
629+
:::
630+
631+
:::{dropdown} Example: Unitless coordinate system
632+
633+
Alternatively, users may choose to define a unitless coordinate system and connect it to the "intrinsic" coordinate system
634+
with a scale transformation that has the appropriate scale factors to convert to physical units.
635+
In the context of multiscales metadata, this could look like this:
636+
637+
```json
638+
{
639+
"multiscales": [
640+
{
641+
"coordinateSystems": [
642+
{
643+
"name": "intrinsic",
644+
"axes": [
645+
{"name": "y", "type": "space", "unit": "micrometer"},
646+
{"name": "x", "type": "space", "unit": "micrometer"}
647+
]
648+
},
649+
{
650+
"name": "array",
651+
"axes": [
652+
{"name": "y", "type": "space"},
653+
{"name": "x", "type": "space"}
654+
]
655+
}
656+
],
657+
"datasets": [
658+
{
659+
"path": "s0",
660+
"coordinateTransformations": [
661+
{
662+
"type": "scale",
663+
"scale": [0.5, 0.5],
664+
"input": "s0",
665+
"output": "intrinsic"
666+
}
667+
]
668+
}
669+
],
670+
"coordinateTransformations": [
671+
{
672+
"type": "scale",
673+
"scale": [2.0, 2.0],
674+
"input": {"name": "intrinsic"},
675+
"output": {"name": "array"}
676+
}
677+
]
678+
}
679+
]
680+
}
681+
```
682+
In this case, the `scale` transformation under `coordinateTransformations`
683+
defines the mapping from the "intrinsic" coordinate system to the unitless "array" coordinate system.
684+
Another transformation (e.g. in a `scene`) could then use the "array" coordinate system as an input or output to define transformations in array units.
685+
:::
686+
687+
688+
623689
#### Matrix transformations
624690
(matrix-trafo-md)=
625691

0 commit comments

Comments
 (0)