Skip to content

Commit 4be616b

Browse files
bentaculumtinevezcmalinmayormsschwartz21
authored
Support predefined object detection shapes (#159)
This adds storing object detections as pre-defined shapes on a geff graph ( #144). We start off with - circles and spheres as type `sphere` with a single number. - 2D ellipses/3D ellipsoids as type `ellipsoid`, represented by a 2x2/3x3covariance matrix. Thoughts: - Convariance matrices: Store full matrix, using appropriate zarr compression for minimal overhead. # Types of Changes - New feature or enhancement Which topics does your change affect? Delete those that do not apply. - Specification - Schema # Checklist Put an x in the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code. - [x] I have read the [developer/contributing](https://github.com/live-image-tracking-tools/geff/blob/main/CONTRIBUTING) docs. - [ ] I have added tests that prove that my feature works in various situations or tests the bugfix (if appropriate). - [x] I have checked that I maintained or improved code coverage. - [x] I have written docstrings and checked that they render correctly. ## If you changed the specification - [x] I have checked that any validation functions and tests reflect the changes. - [x] I have updated the GeffMetadata and the json schema using `pixi run update-schema` if necessary. - [x] I have updated docs/specification.md to reflect the change. - [ ] I have updated implementations to reflect the change. (This can happen in separate PRs on a feature branch, but must be complete before merging into main.) ## If you have added or changed an implementation - [ ] I wrote tests for the new implementation using standard fixtures supplied in conftest.py. - [ ] I updated pyproject.toml with new dependencies if needed. - [ ] I added a function to tests/bench.py to benchmark the new implementation. --------- Co-authored-by: Jean-Yves Tinevez <[email protected]> Co-authored-by: Caroline Malin-Mayor <[email protected]> Co-authored-by: Morgan Schwartz <[email protected]>
1 parent 1cc3a3c commit 4be616b

File tree

4 files changed

+77
-1
lines changed

4 files changed

+77
-1
lines changed

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ Put an x in the boxes that apply. You can also fill these out after creating the
2323

2424
## If you changed the specification
2525
- [ ] I have checked that any validation functions and tests reflect the changes.
26-
- [ ] I have updated the GeffMetadata and the json schema using `pixi run update-schema` if necessary.
26+
- [ ] I have updated the GeffMetadata and the json schema using `pixi run update-json` if necessary.
2727
- [ ] I have updated docs/specification.md to reflect the change.
2828
- [ ] I have updated implementations to reflect the change. (This can happen in separate PRs on a feature branch, but must be complete before merging into main.)
2929

docs/specification.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ The `nodes\props` group is optional and will contain one or more `node property`
4444
- Geff provides special support for spatio-temporal properties, although they are not required. When `axes` are specified in the `geff` metadata, each axis name identifies a spatio-temporal property. Spatio-temporal properties are not allowed to have missing arrays. Otherwise, they are identical to other properties from a storage specification perspective.
4545

4646
- The `seg_id` property is an optional, special node property that stores the segmenatation label for each node. The `seg_id` values do not need to be unique, in case labels are repeated between time points. If the `seg_id` property is not present, it is assumed that the graph is not associated with a segmentation.
47+
48+
- Geff provides special support for predefined shape properties, although they are not required. These currently include: `sphere`, `ellipsoid`. Values can be marked as `missing`, and a geff graph may contain multiple different shape properties. Units of shapes are assumed to be the same as the units on the spatial axes. Otherwise, shape properties are identical to other properties from a storage specification perspective.
49+
- `sphere`: Hypersphere in n spatial dimensions, defined by a scalar radius.
50+
- `ellipsoid`: Defined by a symmetric positive-definite covariance matrix, whose dimensionality is assumed to match the spatial axes.
4751
<!-- Perhaps we just let the user specify the seg id property in the metadata instead? Then you can point it to the node ids if you wanted to -->
4852

4953
!!! note
@@ -83,6 +87,12 @@ Here is a schematic of the expected file structure.
8387
values # shape: (N,) dtype: float32
8488
x/
8589
values # shape: (N,) dtype: float32
90+
radius/
91+
values # shape: (N,) dtype: int | float
92+
missing # shape: (N,) dtype: bool
93+
covariance3d/
94+
values # shape: (N, 3, 3) dtype: float
95+
missing # shape: (N,) dtype: bool
8696
color/
8797
values # shape: (N, 4) dtype: float16
8898
missing # shape: (N,) dtype: bool
@@ -113,6 +123,9 @@ This is a geff metadata zattrs file that matches the above example structure.
113123
{'name': 'y', 'type': "space", 'unit': "micrometers", 'min': 81.667, 'max': 1877.7},
114124
{'name': 'x', 'type': "space", 'unit': "micrometers", 'min': 764.42, 'max': 2152.3},
115125
],
126+
# predefined node attributes for storing detections as spheres or ellipsoids
127+
"sphere": "radius", # optional
128+
"ellipsoid": "covariance3d", # optional
116129
"display_hints": {
117130
"display_horizontal": "x",
118131
"display_vertical": "y",

geff-schema.json

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,32 @@
152152
"description": "Optional list of Axis objects defining the axes of each node in the graph.\nEach object's `name` must be an existing attribute on the nodes. The optional `type` keymust be one of `space`, `time` or `channel`, though readers may not use this information. Each axis can additionally optionally define a `unit` key, which should match the validOME-Zarr units, and `min` and `max` keys to define the range of the axis.",
153153
"title": "Axes"
154154
},
155+
"sphere": {
156+
"anyOf": [
157+
{
158+
"type": "string"
159+
},
160+
{
161+
"type": "null"
162+
}
163+
],
164+
"default": null,
165+
"description": "\n Name of the optional `sphere` property.\n\n A sphere is defined by\n - a center point, already given by the `space` type properties\n - a radius scalar, stored in this property\n ",
166+
"title": "Node property: Detections as spheres"
167+
},
168+
"ellipsoid": {
169+
"anyOf": [
170+
{
171+
"type": "string"
172+
},
173+
{
174+
"type": "null"
175+
}
176+
],
177+
"default": null,
178+
"description": "\n Name of the `ellipsoid` property.\n\n An ellipsoid is assumed to be in the same coordinate system as the `space` type\n properties.\n\n It is defined by\n - a center point :math:`c`, already given by the `space` type properties\n - a covariance matrix :math:`\\Sigma`, symmetric and positive-definite, stored in this\n property as a `2x2`/`3x3` array.\n\n To plot the ellipsoid:\n - Compute the eigendecomposition of the covariance matrix\n :math:`\\Sigma = Q \\Lambda Q^{\\top}`\n - Sample points :math:`z` on the unit sphere\n - Transform the points to the ellipsoid by\n :math:`x = c + Q \\Lambda^{(1/2)} z`.\n ",
179+
"title": "Node property: Detections as ellipsoids"
180+
},
155181
"track_node_props": {
156182
"anyOf": [
157183
{

src/geff/metadata_schema.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,43 @@ class GeffMetadata(BaseModel):
208208
"Each axis can additionally optionally define a `unit` key, which should match the valid"
209209
"OME-Zarr units, and `min` and `max` keys to define the range of the axis.",
210210
)
211+
sphere: str | None = Field(
212+
None,
213+
title="Node property: Detections as spheres",
214+
description=(
215+
"""
216+
Name of the optional `sphere` property.
217+
218+
A sphere is defined by
219+
- a center point, already given by the `space` type properties
220+
- a radius scalar, stored in this property
221+
"""
222+
),
223+
)
224+
ellipsoid: str | None = Field(
225+
None,
226+
title="Node property: Detections as ellipsoids",
227+
description=(
228+
"""
229+
Name of the `ellipsoid` property.
230+
231+
An ellipsoid is assumed to be in the same coordinate system as the `space` type
232+
properties.
233+
234+
It is defined by
235+
- a center point :math:`c`, already given by the `space` type properties
236+
- a covariance matrix :math:`\\Sigma`, symmetric and positive-definite, stored in this
237+
property as a `2x2`/`3x3` array.
238+
239+
To plot the ellipsoid:
240+
- Compute the eigendecomposition of the covariance matrix
241+
:math:`\\Sigma = Q \\Lambda Q^{\\top}`
242+
- Sample points :math:`z` on the unit sphere
243+
- Transform the points to the ellipsoid by
244+
:math:`x = c + Q \\Lambda^{(1/2)} z`.
245+
"""
246+
),
247+
)
211248
track_node_props: dict[Literal["lineage", "tracklet"], str] | None = Field(
212249
None,
213250
description=(

0 commit comments

Comments
 (0)