Skip to content

Commit 7a36e66

Browse files
authored
Merge branch 'main' into translations-in-multiscales
2 parents c90100b + 29d6a9d commit 7a36e66

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

@@ -603,6 +562,113 @@ to do so by estimating the transformations' inverse if they choose to.
603562
```
604563
:::
605564

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

0 commit comments

Comments
 (0)