Open dominikl opened 3 years ago
other elements like mapping family needs to be added: this assumes linear mapping This could also be an opportunity to re-activate the "co-domain" transformations i.e. changes in the device space
Introducing an experimental branch will make sense otherwise we will have a long open PR
A few high-level thoughts, I think the development workflow will come across several repositories (https://github.com/ome/omero-cli-zarr/pull/88 is another example). Completely fine from my side with having an experimental/development branch where PRs get integrated more quickly.
A few additional considerations:
Maybe for default dimensions, this might be nicer:
"default_dimensions" : {
"0": 10,
"2": 2
}
Also, note the discussion of naming style at https://github.com/ome/ngff/issues/54
Strong preference for color_format
over color-format
etc.
for the naming discussion, I am wondering if we should not follow the schema.org rule i.e. colorFormat
concept of group should be supported. We will need support for multiple groups
group : {
"name": "group1",
"visible": True,
"indexes": "1, 2, 5",
"type": "channel" (could be angle)
}
Looking at the BDV xml files, they need support for AffineTransform
for each viewSetup. A viewSetup is either a channel or an angle. There is a transform per timepoint.
The physicalSizeX etc. will need to be known for scale bar but I assume that will be stored elsewhere in the file
Resolution level, viewport could be considered
@jburel If you're suggesting that the ngff spec uses a different naming convention than snake_case
then you should suggest that on https://github.com/ome/ngff/issues/54 since I don't think we want different conventions for different parts of the spec.
I don't quite understand the relevance of https://schema.org/ here. Are you thinking that we might want to extend the schema.org vocabulary with our ngff terms?
My comment is more general that this specific issue. The suggestion of following schema.org is coming from the fact that others efforts e.g. bioschema.org, ro-crate follow that convention so it might make more sense to follow similar rule instead of the snake_case
convention
Are you thinking that we might want to extend the schema.org vocabulary with our ngff terms?
There's a pretty good likelihood that we will eventually want to incorporate schema.org types into our metadata, but that's true for other ontologies & vocabularies as well. The likelihood of being able to find a set which follow the same naming style is basically zero.
I am currently looking at https://www.ebi.ac.uk/spot/oxo/docs/api for a project: mappingTarget
is for example a field returned
With the recent suggestions added, it would look like these:
{
"channels": {
"0": {
"color": "00FF00",
"color_format": "hex",
"color_type": "rgb",
"label": "GFP",
"mapping": {
"coefficient": "1.8",
"family": "exponential",
"reverse": "False"
},
"noise_reduction": "False",
"window": {
"end": 1542.5789794921875,
"max": 1542.5789794921875,
"min": 0.0,
"start": 0.0
}
},
...
},
"color_model": "color",
"default_dimensions": {
"0": 0,
"1": 0
},
"dimensions": "zt",
"group": {
"0": {
"indexes": [
"0",
"2"
],
"type": "channel",
"visible": "True"
}
},
"plane": "xy",
"version": 3
}
Not sure where to put the viewSetup
.
A few initial thoughts while reading https://github.com/ome/omero-cli-render/issues/55#issuecomment-942313450 (without having looked at the notes):
color_format
/color_type
properties might be think we might be moving towards defining a color
dictionary rather than a series of flat keys?dimensions/default_dimensions
: is there an expected overlap/relationship with the axes
metadata? Should these default settings also be within the group
objects?You're right, color as dictionary is better. And default Z/T (dimensions/axis) should be part of the group
. Also dimension
should actually be axis
. And the coefficient
in the channel mapping is now a list (as far as I understand one could have other operations than linear, exponential which might have more than one parameter).
I struggle a bit with a further generalisation of the dimension/axis bit. In general the axis are XYZTC (or whatever order). But they are not the same kind of thing. Channel is a special dimension, and you also still need the concept of a plane, plus extra dimensions. Right? But then @jburel said instead of channels one could also have angles (sorry I still don't really get this bit).
Anyway, at the moment it would look like this:
does the current draft of the rendering model support sparse channel settings or should all channels be specified?
That's a good question too. I don't think we've discussed that yet.
Currently, it looks like if the number of channels
in the omero
data is different from the size_c of the data (or if any of the channels is missing color
) then the image will fail to open in napari
. But it shouldn't be hard to fix this and handle missing channels / colors.
Apologies for missing any discussions on this, but what does "plane": "xy"
and "axes": "zt"
signify?
The proposal at https://github.com/ome/ngff/pull/57 is to specify the types of the various axes, e.g.:
"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"}
],
You need to somehow specify that you're viewing a x,y plane and that the further dimensions are labelled as z and t (in exactly that order). This axis list looks good. But is that ordered? And how would you in that case say you want to show the x,y plane for z-axis 3 by default for example?
The axes
list above is certainly ordered. Already for v0.3
we have "axes": ["z", "y", "x"]
etc, but for v0.4
it's proposed to specify the type
of each axis.
If you have "axes": ["z", "y", "x"]
with "default_dimensions": {"0": 3,}
I think that would do it for "z-axis 3"?
Just being picky, I wonder if default_dimensions
in your examples is really specifying defaultIndices
rather than dimensions?
NB: it's looking like https://github.com/ome/ngff/issues/54 is heading for camelCase
.
But still needs a plane
. Or should one assume from default_dimensions": {"0": 3,}
and axes": ["z", "y", "x"]
that the plane is x,y? That would mean all default_dimensions
have to specified. Yes, it should rather be defaultIndices
indeed.
I think that plane
can default to xy
, so we don't need to specify it. If you choose to specify the x
or y
dimension in the defaultIndices
then I guess you might need to know plane (only if you have size_T > 1 AND size_Z > 1), but we have no way to support that in napari
or vizarr
as far as I can tell (https://napari.org/docs/dev/api/napari.view_layers.Viewer.html#napari.view_layers.Viewer.add_image)
And in genuine 3D viewers (moBie, neuroglancer) I don't think you'll use it either?
I thought the point was to keep things as generic as possible, no matter what's currently supported by our or other software. But if we define the plane is always x/y and the axis are always z and t - like it is now - then this whole discussion is pointless and we can basically take the current output of the render plugin as rendering settings spec (just have to change a few names like z
to default-z
, defaultZ
, default_z
, ...)
plane cannot default to xy
, in our model we have the concept of PlaneDef
and support for xy
, xz
and yz
. This was previously implemented in insight as a slice viewer.
Just a quick, perhaps unrelated question: Is the idea that tool-specific (e.g. rendering specific) metadata becomes part of the "official" ngff spec? I'm wondering because I created this issue with regards to tool-specific metadata. Sorry if this has been answered already elsewhere.
"mapping": {
"coefficients": [
"1.0"
],
"family": "linear",
"reverse": "False"
},
I don't see why coefficients is a list. if you have a mapping function that takes more than one parameter it will have to be a dictionary. The proposal is mixing 2 concepts:
Looking at the BDV example,
<Timepoints type="range">
<first>0</first>
<last>2</last>
</Timepoints>
defaultIndices
will probably need to support range or list of ranges and not only a value
in our case it could be "0": [0,0]
. This adds some complexity in the handling but should hopefully accommodate other viewers' needs
As the axis definition is apparently already in the "general" ngff spec, we might as well use the axis names z, t for the plane and defaultIndices instead of indices. I don't know where/what kind of dictionary this mapping
element should be, nor how/where to add an angle
definition, please just add an example @jburel / @dgault .
@unidesigner : Yes, it's going to be an ngff specfication, but as far as I know there will be places for tool specific metadata too.
{
"views": {
"type": "channel",
"0": {
"color": {
"format": "hex",
"type": "rgb",
"value": "00FF00"
},
"coefficient": "1.8",
"family": "exponential",
"label": "GFP",
"noiseReduction": "False",
"deviceSpaceMapping": [{"reverseIntensity": {"value": True}}],
"window": {
"end": 1542.5789794921875,
"max": 1542.5789794921875,
"min": 0.0,
"start": 0.0
}
},
"1": {
"coefficient": "1.0",
"color": {
"format": "hex",
"type": "rgb",
"value": "FFFFFF"
},
"family": "linear",
"label": "1",
"noiseReduction": "False",
"deviceSpaceMapping": [{"reverseIntensity": {"value": True}}, {"binning": {"0-100": 100, "101-200": 200, "201-255": 255}}]
"window": {
"end": 1555.0537109375,
"max": 1555.0537109375,
"min": 0.0,
"start": 0.0
}
},
"2": {
"coefficient": "1.0",
"color": {
"format": "name",
"type": "lut",
"value": "brgbcmyw"
},
"family": "linear",
"label": "2",
"noiseReduction": "False",
"reverse": "False",
"window": {
"end": 188.89093017578125,
"max": 188.89093017578125,
"min": 0.007875712588429451,
"start": 0.007875712588429451
}
}
},
"colorModel": "color",
"group": {
"0": {
"defaultIndices": {
"t": {
"from": 0,
"to": 0
},
"z": {
"from": 0,
"to": 0
}
},
"indices": [
"0",
"2"
],
"type": "channel",
"visible": "True",
"name": "Group 1"
}
},
"plane": "xy"
}
As mentioned during the call, angle is a new dimension so I have replaced channels
by views
and we identify the views
by its type
. If we have settings for angles and channels, we will have multiple views
entries, this is no different from groups
. I have also added a new entry deviceSpaceMapping
. This is a bit complicated since we need a name and the parameters for the transformation.
For reverseIntensity
, the name is probably enough but it seems strange to just have the name
From discussion today it should probably be
"views": {
"0": {
"channel": "0",
"angle": "1",
"color": {
"format": "hex",
"type": "rgb",
"value": "00FF00"
},
"coefficient": "1.8",
"family": "exponential",
"label": "GFP",
"noiseReduction": "False",
"deviceSpaceMapping": [{"reverseIntensity": {"value": True}}],
"window": {
"end": 1542.5789794921875,
"max": 1542.5789794921875,
"min": 0.0,
"start": 0.0
}
},
"group": {
"0": {
"defaultIndices": {
"t": {
"from": 0,
"to": 0
},
"z": {
"from": 0,
"to": 0
}
},
"indicesChannel": [
"0",
"2"
],
"indicesAngle": [
"1"
],
"visible": "True",
"name": "Group 1"
}
},
"plane": "xy"
Alternative:
"indices": {
"channel": {
"0",
"1"
},
"angle": {
"2"
}
},
"deviceSpaceMapping": [{"reverseIntensity": {"value": True}}],
could be a bit more concise
"deviceSpaceMapping": [{"reverseIntensity": True}],
(unless this is trying to model omero.rtypes.rbool
, or there's other info that could be included in future?)
@will-moore we could simplify, I was trying to go for the same pattern for each entry
Another thought concerning validation: I don't know what schema etc we might use (e.g. SALAD at https://github.com/ome/ngff/pull/69 or https://wiki.ebrains.eu/bin/view/Collabs/openminds/Documentation/Implementation%20details/#HTheopenMINDSsyntax) but it seems that validation won't work well if the attribute keys (fields) are variable (not defined by the spec). E.g. a key of "0"
or "50"
for channel index is hard to validate, since you don't have named fields. Same for channel/angle/otherDimensionName
(unless we can state in the spec that only channel
and angle
are supported?
@will-moore good point
Updated example taking the latest discussions into account:
{
"colorModel": "color",
"group": [
{
"indices": {
"angle": [],
"channel": [
"0",
"2"
],
"t": {
"from": 0,
"to": 0
},
"z": {
"from": 0,
"to": 0
}
},
"name": "Group 0",
"visible": "True"
}
],
"plane": "xy",
"version": 3,
"views": [
{
"angle": "",
"channel": "0",
"coefficient": "1.8",
"color": {
"format": "hex",
"type": "rgb",
"value": "00FF00"
},
"deviceSpaceMapping": {
"reverseIntensity": "False"
},
"family": "exponential",
"label": "GFP",
"noiseReduction": "False",
"window": {
"end": 1542.5789794921875,
"max": 1542.5789794921875,
"min": 0.0,
"start": 0.0
}
},
{
"angle": "",
"channel": "1",
"coefficient": "1.0",
"color": {
"format": "hex",
"type": "rgb",
"value": "FFFFFF"
},
"deviceSpaceMapping": {
"reverseIntensity": "False"
},
"family": "linear",
"label": "1",
"noiseReduction": "False",
"window": {
"end": 1555.0537109375,
"max": 1555.0537109375,
"min": 0.0,
"start": 0.0
}
},
{
"angle": "",
"channel": "2",
"coefficient": "1.0",
"color": {
"format": "name",
"type": "lut",
"value": "brgbcmyw"
},
"deviceSpaceMapping": {
"reverseIntensity": "False"
},
"family": "linear",
"label": "2",
"noiseReduction": "False",
"window": {
"end": 188.89093017578125,
"max": 188.89093017578125,
"min": 0.007875712588429451,
"start": 0.007875712588429451
}
}
]
}
Capturing discussion from Today
I am not sure about the groupVisible
cc @dominikl
{
"colorModel": "color",
"plane": "xy",
"version": 3,
"views": [
{
"angle": "",
"channel": "0",
"coefficient": "1.8",
"color": {
"format": "hex",
"type": "rgb",
"value": "00FF00"
},
"deviceSpaceMapping": {
"reverseIntensity": "False"
},
"family": "exponential",
"label": "GFP",
"noiseReduction": "False",
"window": {
"end": 1542.5789794921875,
"max": 1542.5789794921875,
"min": 0.0,
"start": 0.0
},
"active": "True",
"inGroup": " Group 0",
"groupVisible": "True",
"t": {
"from": 0,
"to": 0
},
"z": {
"from": 0,
"to": 0
}
},
{
"angle": "",
"channel": "1",
"coefficient": "1.0",
"color": {
"format": "hex",
"type": "rgb",
"value": "FFFFFF"
},
"deviceSpaceMapping": {
"reverseIntensity": "False"
},
"family": "linear",
"label": "1",
"noiseReduction": "False",
"window": {
"end": 1555.0537109375,
"max": 1555.0537109375,
"min": 0.0,
"start": 0.0
},
"active": "False",
"inGroup": " Group 1",
"groupVisible": "False",
"t": {
"from": 0,
"to": 0
},
"z": {
"from": 0,
"to": 0
}
},
{
"angle": "",
"channel": "2",
"coefficient": "1.0",
"color": {
"format": "name",
"type": "lut",
"value": "brgbcmyw"
},
"deviceSpaceMapping": {
"reverseIntensity": "False"
},
"family": "linear",
"label": "2",
"noiseReduction": "False",
"window": {
"end": 188.89093017578125,
"max": 188.89093017578125,
"min": 0.007875712588429451,
"start": 0.007875712588429451
},
"active": "True",
"inGroup": " Group 0",
"groupVisible": "True",
"t": {
"from": 0,
"to": 0
},
"z": {
"from": 0,
"to": 0
}
},
]
}
@jburel I like the fact that it's easy for a viewer that doesn't support groups to ignore them. And hopefully not too much work for a viewer that does support them. NB: the JSON is not quite formatted correctly? e.g. "window" and "active" are sibling keys in the first and 2nd view, but at different levels in the 3rd. The indentation is inconsistent so it's a bit hard to be sure what's meant?
Is it possible to load the same channel at 2 different angles or Z/T indices?
One option I had imagined from the discussion was to try Dom's last example above, and nest the views within the groups, replacing angle
and channel
with the view that has angle and channel E.g, a single group with 2 channels:
{
"colorModel": "color",
"group": [
{
"indices": {
"views": [
{
"angle": "",
"channel": "0",
"color": {}... etc.
},
{
"angle": "",
"channel": "1",
"color": {}... etc.
}
],
"t": {
"from": 0,
"to": 0
},
"z": {
"from": 0,
"to": 0
}
},
"name": "Group 0",
"visible": "True"
}
],
"plane": "xy",
"version": 3
}
(just in case that has any appeal)?
I wonder if we should document the use-cases we're trying to support. E.g. do any viewers allow you to show different channels (or the same channel) at different Z/T indices or angles? The pathviewer example was helpful in directing the discussions, but there were other viewers mentioned (BigDataViewer etc) that it would be handy if everyone was on the same page.
To summarise grouping of channels in pathviewer:
"groups": [{"channels": [0,1,2],"name": "Cycle1"}, {"channels": [3,4,5],"name": "Cycle2"}]
@will-moore formatting should be fixed
"groups: [
{
"views": [id1, id2],
"name": "Cycle1",
"visible": "True",
},
{
"views": [id3],
"name": "Cycle2",
"visible": "True",
},
],
"views": [
{
"id": xxx,
"angle": "",
"channel": "0",
"color": {}... etc.
},
{
"id": xxx,
"angle": "",
"channel": "1",
"color": {}... etc.
}
],
"colorModel": "color",
"defaultPlane": [3,4]
"defaultIndices" = [5,10:20,0:200,null], // (t,z, x, y) view only 0-200 on x axis and all values on y axis
"version": 3
Fixing a few things:
null
in the defaultIndices.@id
for IDs.visible
to each view, as well as on group "defaultIndices": [5, null, "10:20", 250, 750]
{
"groups": [
{
"views": ["view1", "view2"],
"name": "Cycle1",
"visible": true
},
{
"views": ["view3"],
"name": "Cycle2",
"visible": true
}
],
"views": [
{
"@id": "view1",
"channel": 0,
"angle": 20,
"visible": true,
"color": {} //... etc.
},
{
"@id": "view2",
"channel": 1,
"angle": 30,
"visible": false,
"color": {} //... etc.
},
{
"@id": "view3",
"channel": 2,
"angle": 10,
"visible": true,
"color": {} //... etc.
}
],
"colorModel": "color",
// e.g. shape is (t,c,z,y,x, angle)
"defaultIndices": [5, null, "10:20", null, null, null], // default view: t=5 and range 10-20 on z axis
// we want to view y,x plane by default
"defaultPlane": [3, 4],
}
edit: @will-moore I have added angle so people don't think we dropped it during our brainstorming
I removed angle since it's not yet allowed as a dimension type by the spec v0.3 or v0.4 proposal at https://github.com/ome/ngff/pull/57/files#diff-ffe6148e5d9f47acc4337bb319ed4503a810214933e51f5f3e46a227b10e3fcdR214 Unless you want to suggest an update to that PR, or add "angle" as a specified type when we add rendering?
For the spec that we propose when ready we can omit angle if we are not ready at the ngff spec level yet. This is to avoid confusion amongst people currently involve in this discussion
With the current specification in mind
We should have something like
renderingSettings
: a collection of renderingDefinition
objects
"renderingDefinition": {
"@id": "renderingDef1"
"groups": [
{
"views": ["view1", "view2"],
"name": "Cycle1",
"visible": "True"
},
{
"views": ["view3"],
"name": "Cycle2",
"visible": "True"
}
],
"views": [
{
"@id": "view1",
"channel": 0,
"visible": true,
"coefficient": "1.0",
"color": {
"format": "name",
"type": "lut",
"value": "brgbcmyw.lut"
},
"deviceSpaceMapping": {
"reverseIntensity": "False"
},
"family": "linear",
"label": "GFP",
"noiseReduction": "False",
"window": {
"end": 188.89093017578125,
"max": 188.89093017578125,
"min": 0.007875712588429451,
"start": 0.007875712588429451
}
},
{
"@id": "view2",
"channel": 1,
"visible": "False",
"coefficient": "1.8",
"color": {
"format": "hex",
"type": "rgb",
"value": "00FF00"
},
"deviceSpaceMapping": {
"reverseIntensity": "False"
},
"family": "exponential",
"label": "DAPI",
"noiseReduction": "False",
"window": {
"end": 1542.5789794921875,
"max": 1542.5789794921875,
"min": 0.0,
"start": 0.0
}
},
{
"@id": "view3",
"channel": 2,
"visible": "True",
"color": {
"format": "hex",
"type": "rgb",
"value": "FFFFFF"
},
"deviceSpaceMapping": {
"reverseIntensity": "False"
},
"family": "linear",
"label": "OOOO",
"noiseReduction": "False",
"window": {
"end": 1555.0537109375,
"max": 1555.0537109375,
"min": 0.0,
"start": 0.0
}
}
],
"colorModel": "color",
// e.g. shape is (t,c,z,y,x)
"defaultIndices": [5, null, 10:20, null, null], // default view: t=5 and range 10-20 on z axis
// we want to view y,x plane by default
"defaultPlane": [3, 4],
"resolution": 0
}
One remaining question is about the LUT, it is currently identify by a name. Is that acceptable? or do we want to ship the binary? A viewer will still need to be able to read the LUT. I think the name of the lut
e.g. a.lut
will be enough for most cases
i.e.
"color": {
"format": "name",
"type": "lut",
"value": "brgbcmyw"
},
@will-moore I have added a new parameter resolution
. This is a value currently missing in our model and important when browsing pyramid for example
Yes, currently PathViewer's channel group specification allows for a channel to be in more than one group. There's lots of history there and @emilroz, @erindiel, and @knabar would be your authorities.
Suggestion from @chris-allan: use term palette
instead LUT
see https://en.wikipedia.org/wiki/List_of_color_palettes
The render plugin is a good starting point to play around with different ideas. Wonder if we should have an 'experimental' branch maybe? /cc @jburel @dgault @francesw
Here's a first attempt, kind of a hybrid of the current render plugin output and the current NGFF draft specification (code see draft PR #54 ):
Instead of
defaultZ/T
it's more genericdefault-dimension-
and what the dimensions actually mean is specified indimensions
, what a plane actually means likewise inplane
. Also the color can be more generic. See above for the common html color specification, but it could also hold lookup tables (e.g. specified by aname
or maybeurl
, etc.), e.g.Edit: Actually
default-dimension-
should better be a list, not several keys.