Skip to content

Commit f8b9769

Browse files
authored
Merge branch 'main' into translations-in-multiscales
2 parents 7a36e66 + 4fc7355 commit f8b9769

3 files changed

Lines changed: 194 additions & 101 deletions

File tree

.codespellrc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[codespell]
2+
# Ref: https://github.com/codespell-project/codespell#using-a-config-file
3+
skip = .git,.codespellrc,references.bib
4+
check-hidden = true
5+
# ignore-regex =
6+
ignore-words-list = commend,Fuchsia

index.md

Lines changed: 177 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -275,9 +275,9 @@ In contrast, discrete axes (`"discrete" : true`) may be indexed only by integers
275275
Axes representing a channel, coordinate, or displacement are usually discrete.
276276

277277
```{note}
278-
The most common methods for interpolation are "nearest neighbor", "linear", "cubic", and "windowed sinc".
278+
The most common methods for interpolation are "nearest", "linear", "bspline-cubic", and "windowed sinc" (see {cite:t}`thevenaz2000image`, section 8).
279279
Here, we refer to any method that obtains values at real-valued coordinates using discrete samples as an "interpolator".
280-
As such, label images may be interpolated using "nearest neighbor" to obtain labels at points along the continuum.
280+
As such, label images may be interpolated using "nearest" to obtain labels at points along the continuum.
281281
```
282282

283283
#### Coordinate convention
@@ -420,8 +420,8 @@ The following transformations are supported:
420420
| [`affine`](#affine-md) | one of:<br>`"affine":List[List[number]]`,<br>`"path":str` | 2D affine transformation matrix stored either with JSON (`affine`) or as a Zarr array at a location in this container (`path`). |
421421
| [`rotation`](#rotation-md) | one of:<br>`"rotation":List[List[number]]`,<br>`"path":str` | 2D rotation transformation matrix stored as an array stored either with json (`rotation`) or as a Zarr array at a location in this container (`path`).|
422422
| [`sequence`](#sequence-md) | `"transformations":List[Transformation]` | sequence of transformations. Applying the sequence applies the composition of all transforms in the list, in order. |
423-
| [`displacements`](#coordinates-displacements-md) | `"path":str` | Displacement field transformation located at `path`. |
424-
| [`coordinates`](#coordinates-displacements-md) | `"path":str` | Coordinate field transformation located at `path`. |
423+
| [`displacements`](#coordinates-displacements-md) | `"path":str` <br> `"interpolation":str` | Displacement field transformation located at `path`. |
424+
| [`coordinates`](#coordinates-displacements-md) | `"path":str` <br> `"interpolation":str` | Coordinate field transformation located at `path`. |
425425
| [`bijection`](#bijection-md) | `"forward":Transformation`<br>`"inverse":Transformation` | An invertible transformation providing an explicit forward transformation and its inverse. |
426426
| [`byDimension`](#bydimension-md) | `"transformations":List[Transformation]`.<br>Transformations in the array MUST have<br>`"input_axes": List[number]`, <br> and `"output_axes": List[number]` | A high dimensional transformation using lower dimensional transformations on subsets of dimensions. |
427427

@@ -462,7 +462,7 @@ i.e., the mapping from the first input axis to the first output axis is determin
462462
Conforming readers:
463463
- MUST parse `identity`, `scale`, `translation` transformations;
464464
- SHOULD parse `mapAxis`, `affine`, `rotation` transformations;
465-
- SHOULD display an informative warning if encountering transformations that cannot be parsed or displayed by a viewer;
465+
- SHOULD display an informative warning if encountering transformations that cannot be parsed or displayed by a consumer;
466466
- SHOULD be able to apply transformations to points;
467467
- SHOULD be able to apply transformations to images;
468468

@@ -562,6 +562,12 @@ to do so by estimating the transformations' inverse if they choose to.
562562
```
563563
:::
564564

565+
```{note}
566+
Exact reproducibility of pixel values for images transformed and resampled by
567+
the transformation types here may differ across implementation and is therefore
568+
out of the scope of this specification.
569+
```
570+
565571
**Transformations in array coordinate units**:
566572
Some applications might prefer to define points, regions-of-interest or transformation parameters
567573
in array coordinates (also referred to as pixel coordinates) rather than physical units.
@@ -1011,100 +1017,155 @@ and is invertible.
10111017
##### coordinates and displacements
10121018
(coordinates-displacements-md)=
10131019

1014-
`coordinates` and `displacements` transformations store coordinates or displacements in an array
1015-
and interpret them as a vector field that defines a transformation.
1016-
The arrays must have a dimension corresponding to every axis of the input coordinate system
1017-
and one additional dimension to hold components of the vector.
1018-
Applying the transformation amounts to looking up the appropriate vector in the array,
1019-
interpolating if necessary,
1020-
and treating it either as a position directly (`coordinates`)
1021-
or a displacement of the input point (`displacements`).
1022-
1023-
These transformation types refer to an array at location specified by the `path` parameter.
1024-
The input and output coordinate systems for these transformations (`input` / `output` coordinate systems)
1025-
constrain the array size and the coordinate system metadata for the array (field `coordinateSystem`).
1026-
1027-
* If the input coordinate system has `N` axes,
1028-
the array at location path MUST have `N+1` dimensions
1029-
* The field coordinate system MUST contain an axis identical to every axis
1030-
of its input coordinate system in the same order.
1031-
* The field coordinate system MUST contain an axis with type `coordinate` or `displacement`, respectively,
1032-
for transformations of type `coordinates` or `displacements`.
1033-
* This SHOULD be the last axis (contiguous on disk when c-order).
1034-
* If the output coordinate system has `M` axes,
1035-
the length of the array along the `coordinate`/`displacement` dimension MUST be of length `M`.
1036-
1037-
The `i`th value of the array along the `coordinate` or `displacement` axis refers to the coordinate or displacement
1038-
of the `i`th output axis. See the example below.
1039-
1040-
`coordinates` and `displacements` transformations are not invertible in general,
1020+
`coordinates` and `displacements` transformations store a vector field of arbitrary sampling density in an array,
1021+
defining a mapping from an input coordinate system to an output coordinate system.
1022+
The array contains either coordinates (absolute positions)
1023+
or displacements (relative shifts) for each point in the input space.
1024+
1025+
```{hint}
1026+
The `coordinates` and `displacements` transformations are not invertible in general,
10411027
but implementations MAY approximate their inverses.
1028+
```
1029+
1030+
**Array Structure**
1031+
1032+
The array containing the coordinates or displacements MUST:
1033+
- be a regular grid of vectors.
1034+
The vectors are stored in an array, the coordinates of which can be mapped
1035+
to the corresponding coordinates in the input coordinate system via a coordinate transformation (see details below).
1036+
- have one dimension corresponding to every axis of the input coordinate system
1037+
- have one additional dimension to hold components of the vector (either coordinates or displacements)
1038+
- only be used to represent transformations between coordinate systems that are defined in smooth, regularly sampled coordinate arrays.
1039+
10421040
Metadata for these coordinate transforms have the following fields:
10431041

10441042
**path**
10451043
: The location of the coordinate array in this (or another) container.
10461044

1045+
**interpolation**
1046+
: The interpolation attributes MAY be provided.
1047+
Its value indicates the interpolation to use if transforming points not on the array's discrete grid.
1048+
1049+
The interpolation methods listed in this specification document refer to the methods described in {cite:t}`thevenaz2000image` and are not exhaustive.
1050+
- `nearest` for nearest neighbor interpolation (see {cite:t}`thevenaz2000image`, section 8.1),
1051+
- `linear` for linear interpolation (default, see {cite:t}`thevenaz2000image`, section 8.2),
1052+
- `bspline-cubic` for cubic interpolation (see {cite:t}`thevenaz2000image`, section 8.3 on "cubic B-splines).
1053+
1054+
Consumers SHOULD clearly communicate to users if a different interpolation method is used.
1055+
1056+
```{hint}
1057+
The `interpolation` field refers to the method that is used to interpolate the `coordinate` or `displacement` array,
1058+
*not* the method used to interpolate the image when applying the transformation to an image.
1059+
The `interpolation` field, if provided, is not normative in the sense that usage of a different method is invalid under the spec.
1060+
Implementations may prefer to use faster methods for rendering (i.e., `linear` or `nearest`) but this may lead to pathological cases:
1061+
- If `nearest` interpolation is used for a `coordinates` transformation,
1062+
the transformed image collapses into a single point at the nearest coordinate in the coordinate field.
1063+
- If `nearest` interpolation is used for a `displacements` transformation,
1064+
the transformed image is piecewise constant with discontinuities at the boundaries between nearest neighbor regions.
1065+
1066+
While choosing the specified interpolation methods can help to avoid these pathologies,
1067+
implementations of the specified interpolation methods may still differ in their results.
1068+
An exact reproducibility of pixel values for images transformed and resampled by this transformation is therefore out of the scope of this specification.
1069+
```
1070+
1071+
**Array metadata**
10471072

10481073
For both `coordinates` and `displacements`,
1049-
the array data at referred to by `path` MUST define coordinate system
1050-
and coordinate transform metadata:
1051-
1052-
* Every axis name in the `coordinateTransform`'s `input`
1053-
MUST appear in the coordinate system.
1054-
* The array dimension corresponding to the `coordinate` or `displacement` axis
1055-
MUST have length equal to the number of dimensions of the `coordinateTransform` `output`
1056-
* If the input coordinate system `N` axes,
1057-
then the array data at `path` MUST have `(N + 1)` dimensions.
1058-
* SHOULD have a `name` identical to the `name` of the corresponding `coordinateTransform`.
1059-
1060-
For `coordinates`:
1061-
1062-
* `coordinateSystem` metadata MUST have exactly one axis with `"type" : "coordinate"`
1063-
* the shape of the array along the "coordinate" axis must be exactly `N`
1064-
1065-
For `displacements`:
1066-
1067-
* `coordinateSystem` metadata MUST have exactly one axis with `"type" : "displacement"`
1068-
* the shape of the array along the "displacement" axis must be exactly `N`
1069-
* input and output coordinate systems MUST have an equal number of dimensions.
1070-
1071-
:::{dropdown} Example 1
1072-
For example, in 1D:
1074+
the array data referred to by `path` MUST define the following metadata fields:
1075+
1076+
* `coordinateSystems`: MUST contain a [coordinate system](#coordinatesystems-metadata) with the following properties:
1077+
- Include all axes of the input coordinate system (in the same order).
1078+
- Include one additional axis of `"type": "coordinate"` (for coordinates transformations) or `"type": "displacement"` (for displacements transformations).
1079+
- The additional axis should be the last axis (for contiguous memory layout in C-order).
1080+
- The `name` of this coordinate system SHOULD be the same as the `name` of the corresponding coordinate transformation.
1081+
1082+
* `coordinateTransformations`: Defines how to map from the coordinate system of the array into a physical coordinate system
1083+
(e.g. the resolution at which the vector field is sampled). MUST contain a single transformation with the following properties:
1084+
- `type`: The type of the transformation; MUST be one of [`identity`](#identity-md), [`scale`](#scale-md)
1085+
or a [`sequence`](#sequence-md) of a [scale](#scale-md) followed by a [translation](#translation-md).
1086+
- `output`: The name of the coordinate system defined in the `coordinateSystems` field of the array metadata.
1087+
1088+
*Note*: The `input` field is omitted, as it is implicitly the pixel coordinate system of the array
1089+
(defined by the first `N` axes of the array's `coordinateSystem`).
1090+
1091+
**Constraints**
1092+
1093+
The array at `path` MUST satisfy:
1094+
1095+
- **Dimensionality**: If the input coordinate system has `N` axes, the array at location `path` MUST have `N+1` dimensions.
1096+
- **Vector dimension length**:
1097+
- For `coordinates` transformations, the length of the array along the `coordinate` dimension (last axis) MUST equal `M`,
1098+
the number of axes in the output coordinate system.
1099+
- For `displacements` transformations, the length of the array along the `displacement` dimension (last axis) MUST equal `N`,
1100+
the number of axes in the input (and output) coordinate system. `displacements` require `M=N`.
1101+
- **Vector component mapping**: The `i`th value of the array along the `coordinate` or `displacement` axis refers to the `i`th output axis.
1102+
1103+
```{hint}
1104+
Applying the transformation to a point `x` in the input coordinate system amounts to following the following steps:
1105+
1. Use the inverse of the transformation found in the vector field's metadata under `coordinateTransformations`
1106+
to map the input point `x` into the corresponding array coordinate `a`.
1107+
2. Look up the vector in the array corresponding to that point's coordinates in the array's coordinate system.
1108+
3. If the point (`a`) does not correspond to a discrete point in the `coordinate` or `displacement` array,
1109+
interpolate the vector field to obtain a vector for the input point.
1110+
4. Treat the result either as
1111+
- an absolute position (`coordinates`) or
1112+
- a displacement to add to the input point `x` (`displacements`).
1113+
```
1114+
1115+
:::{dropdown} Example 1: 1D coordinate transformation
1116+
For example, in 1D, a coordinate field transformation mapping from an input coordinate system `input`
1117+
to an output coordinate system `output` would have metadata such as:
10731118
```json
10741119
{
10751120
"name" : "a coordinate field transform",
10761121
"type": "coordinates",
1077-
"path" : "i2xCoordinates",
1078-
"input" : "i",
1079-
"output" : "x",
1122+
"path" : "coordinateTransformations/i2xCoordinates",
1123+
"input" : "input",
1124+
"output" : "output",
10801125
"interpolation" : "nearest"
10811126
}
10821127
```
10831128

1084-
where we assume input spaces `i` and `x` are defined elsewhere.
1085-
Example metadata for the array data at path `coordinates` above:
1129+
where we assume input coordinate systems `input` and `output` are defined elsewhere.
1130+
Example metadata under the attributes of the zarr array at path `coordinateTransformations/i2xCoordinates` above:
10861131

10871132
```json
10881133
{
1089-
"coordinateSystems" : [
1090-
{
1091-
"name" : "a coordinate field transform",
1092-
"axes" : [
1093-
{ "name": "i", "type": "space", "discrete": true },
1094-
{ "name": "c", "type": "coordinate", "discrete": true }
1095-
]
1096-
}
1097-
],
1098-
"coordinateTransformations" : [
1099-
{
1100-
"type" : "identity",
1101-
"output" : "a coordinate field transform"
1102-
}
1103-
]
1134+
"ome": {
1135+
"coordinateSystems" : [
1136+
{
1137+
"name" : "a coordinate field transform",
1138+
"axes" : [
1139+
{ "name": "i", "type": "space", "discrete": true },
1140+
{ "name": "c", "type": "coordinate", "discrete": true }
1141+
]
1142+
}
1143+
],
1144+
"coordinateTransformations" : [
1145+
{
1146+
"type" : "identity",
1147+
"output" : "a coordinate field transform"
1148+
}
1149+
]
1150+
}
11041151
}
11051152
```
11061153

1107-
If the array in `coordinates` contains the data: `[-9, 9, 0]`, then this metadata defines the function:
1154+
Here, the axis `i` refers to the input positions along the `i`-axis,
1155+
which equal array indices in this case as indicated by the `identity` transformation.
1156+
The `c` axis holds the corresponding output coordinates.
1157+
1158+
If the array in `coordinates` contains the data:
1159+
```
1160+
[
1161+
[-9], // Output coordinate for index=0, i=0
1162+
[9], // Output coordinate for index=1, i=1
1163+
[0] // Output coordinate for index=2, i=2
1164+
]
1165+
```
1166+
1167+
then this metadata defines the following function to map
1168+
the `i` axis (`input` coordinate system) to the `x` axis (`output` coordinate system):
11081169

11091170
```
11101171
x =
@@ -1114,44 +1175,58 @@ x =
11141175
```
11151176
:::
11161177

1117-
:::{dropdown} Example 2
1178+
:::{dropdown} Example 2: 1D displacement transformation
11181179
A 1D example displacement field:
11191180
```json
11201181
{
11211182
"name" : "a displacement field transform",
11221183
"type": "displacements",
11231184
"path" : "displacements",
1124-
"input" : "i",
1125-
"output" : "x",
1185+
"input" : "input",
1186+
"output" : "output",
11261187
"interpolation" : "linear"
11271188
}
11281189
```
11291190

1130-
where we assume input spaces `i` and `x` are defined elsewhere.
1131-
Example metadata for the array data at path `displacements` above:
1191+
where we assume input coordinate systems `input` and `output` are defined elsewhere.
1192+
Example metadata under the attributes of the zarr array at path `displacements` above:
11321193

11331194
```json
11341195
{
1135-
"coordinateSystems" : [
1136-
{
1137-
"name" : "a displacement field transform",
1138-
"axes" : [
1139-
{ "name": "x", "type": "space", "unit" : "nanometer" },
1140-
{ "name": "d", "type": "displacement", "discrete": true }
1141-
]
1142-
}
1143-
],
1144-
"coordinateTransformations" : [
1145-
{
1146-
"type" : "scale",
1147-
"scale" : [2, 1],
1148-
"output" : "a displacement field transform"
1149-
}
1150-
]
1196+
"ome": {
1197+
"coordinateSystems" : [
1198+
{
1199+
"name" : "a displacement field transform",
1200+
"axes" : [
1201+
{ "name": "x", "type": "space", "unit" : "nanometer" },
1202+
{ "name": "d", "type": "displacement", "discrete": true }
1203+
]
1204+
}
1205+
],
1206+
"coordinateTransformations" : [
1207+
{
1208+
"type" : "scale",
1209+
"scale" : [2, 1],
1210+
"output" : "a displacement field transform"
1211+
}
1212+
]
1213+
}
11511214
}
11521215
```
11531216

1154-
If the array in `displacements` contains the data: `[-1, 0, 1]`,
1217+
Since the input and output coordinate system may be defined in physical units,
1218+
a scale transformation is needed to map the displacement vectors into the same physical units as the input point.
1219+
1220+
If the array in `displacements` contains the data:
1221+
1222+
```
1223+
[
1224+
[-1], // Displacement for index=0, x=0
1225+
[0], // Displacement for index=1, x=2
1226+
[1] // Displacement for index=2, x=4
1227+
]
1228+
```
1229+
11551230
this transformation maps the point `[1.0]` to the point `[0.5]`.
11561231
A scale transformation maps the array coordinates to the `x` axis.
11571232
Using the inverse of the scale transform, we see that we need the position `0.5` in array coordinates.
@@ -1161,7 +1236,7 @@ That value gives us the displacement of the input point,
11611236
hence the output is `1.0 + (-0.5) = 0.5`.
11621237
:::
11631238

1164-
:::{dropdown} Example 3
1239+
:::{dropdown} Example 3: 2D displacement transformation
11651240

11661241
In this example, the array located at `displacementField` MUST have three dimensions.
11671242
One dimension MUST correspond to an axis with `type : displacement` (in this example, the last dimension),
@@ -1187,7 +1262,8 @@ The metadata at location `displacementField` should have a coordinate system suc
11871262
```json
11881263
"coordinateSystems" : [
11891264
{ "name" : "in", "axes" : [
1190-
{"name":"y"}, {"name":"x"},
1265+
{"name":"y"},
1266+
{"name":"x"},
11911267
{"name":"d", "type":"displacement", "discrete":true} ]
11921268
}
11931269
]

references.bib

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,14 @@ @software{ngff_spec_latest
2222
doi = {10.5281/zenodo.4282106},
2323
url = {https://ngff.openmicroscopy.org/latest/},
2424
}
25+
26+
@article{thevenaz2000image,
27+
title={Image interpolation and resampling},
28+
author={Th{\'e}venaz, Philippe and Blu, Thierry and Unser, Michael},
29+
journal={Handbook of medical imaging, processing and analysis},
30+
volume={1},
31+
number={1},
32+
pages={393--420},
33+
year={2000},
34+
url={https://bigwww.epfl.ch/publications/thevenaz9901.pdf}
35+
}

0 commit comments

Comments
 (0)