-
Notifications
You must be signed in to change notification settings - Fork 57
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Label stack support #1816
Label stack support #1816
Changes from 15 commits
e3e85e7
635b6d3
1febf39
67e1084
4e2613c
649520e
dfde1da
a4f9a4c
c00d98a
c8be170
4ee11b6
3dd51fa
bda29b9
8f66729
584083d
bbaa9e3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1362,13 +1362,13 @@ var project; | |
stacks: stacks | ||
}; | ||
CATMAID.layoutStackViewers(); | ||
// Make all tile layers visible, they have been initialized | ||
// Make all stack layers visible, they have been initialized | ||
// invisible. | ||
for (var i=0; i<loadedStackViewers.length; ++i) { | ||
var sv = loadedStackViewers[i]; | ||
var tileLayers = sv.getLayersOfType(CATMAID.TileLayer); | ||
for (var j=0; j<tileLayers.length; ++j) { | ||
var tl = tileLayers[j]; | ||
var stackLayers = sv.getLayersOfType(CATMAID.StackLayer); | ||
for (var j=0; j<stackLayers.length; ++j) { | ||
var tl = stackLayers[j]; | ||
tl.setOpacity(1.0); | ||
tl.redraw(); | ||
} | ||
|
@@ -1517,7 +1517,7 @@ var project; | |
* @param {StackViewer} stackViewer Viewer to which to add the stack. | ||
* @param {number} mirrorIndex Optional mirror index, defaults to | ||
* the first available. | ||
* @param {Boolean} hide The stack's tile layer will initially be | ||
* @param {Boolean} hide The stack's layer will initially be | ||
* hidden. | ||
* @return {Promise} A promise yielding the stack viewer | ||
* containing the new stack. | ||
|
@@ -1590,40 +1590,45 @@ var project; | |
}); | ||
} | ||
|
||
function loadStack(e, stackViewer, hideTileLayer) { | ||
function loadStack(e, stackViewer, hideStackLayer) { | ||
var useExistingViewer = typeof stackViewer !== 'undefined'; | ||
|
||
var stack = new CATMAID.Stack.fromStackInfoJson(e); | ||
|
||
// If this is a label stack, not a raw stack, create a label annotation | ||
// manager. | ||
// TODO: should eventually use a backend image label space instead. | ||
if (!!stack.labelMetadata()) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree, using the |
||
CATMAID.LabelAnnotations.get(stack); | ||
} | ||
|
||
if (!useExistingViewer) { | ||
stackViewer = new CATMAID.StackViewer(project, stack); | ||
} | ||
|
||
document.getElementById( "toolbox_project" ).style.display = "block"; | ||
|
||
var tilelayerConstructor = CATMAID.TileLayer.Settings.session.prefer_webgl ? | ||
CATMAID.PixiTileLayer : | ||
CATMAID.TileLayer; | ||
var tilelayer = new tilelayerConstructor( | ||
var stackLayerConstructor = CATMAID.StackLayer.preferredConstructorForStack(); | ||
var stackLayer = new stackLayerConstructor( | ||
stackViewer, | ||
"Image data (" + stack.title + ")", | ||
stack, | ||
mirrorIndex, | ||
!hideTileLayer, | ||
hideTileLayer ? 0 : 1, | ||
!hideStackLayer, | ||
hideStackLayer ? 0 : 1, | ||
!useExistingViewer, | ||
CATMAID.TileLayer.Settings.session.linear_interpolation, | ||
CATMAID.StackLayer.INTERPOLATION_MODES.INHERIT, | ||
true); | ||
|
||
if (!useExistingViewer) { | ||
stackViewer.addLayer( "TileLayer", tilelayer ); | ||
stackViewer.addLayer("StackLayer", stackLayer); | ||
|
||
project.addStackViewer( stackViewer ); | ||
|
||
// refresh the overview handler to also register the mouse events on the buttons | ||
stackViewer.layercontrol.refresh(); | ||
} else { | ||
stackViewer.addStackLayer(stack, tilelayer); | ||
stackViewer.addStackLayer(stack, stackLayer); | ||
} | ||
|
||
CATMAID.ui.releaseEvents(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
(function (CATMAID) { | ||
|
||
"use strict"; | ||
|
||
class LabelAnnotations { | ||
constructor() { | ||
this.groupManagingStack = new Map(); | ||
this.managers = new Map(); | ||
this.active = undefined; | ||
} | ||
|
||
activate(stackID) { | ||
this.active = stackID; | ||
} | ||
|
||
clear() { | ||
for (const [_stack, manager] of this.managers.entries()) manager.unregister(); | ||
this.managers.clear(); | ||
this.groupManagingStack.clear(); | ||
this.active = undefined; | ||
} | ||
|
||
get(stack) { | ||
let manager = this.managers.get(stack.id); | ||
|
||
if (!manager) { | ||
// Find all stack groups to which this stack belongs. | ||
return CATMAID.fetch(project.id + '/stack/' + stack.id + '/groups') | ||
.then(response => | ||
// Get the info of all of these groups. | ||
Promise.all(response.stack_group_ids.map( | ||
sg_id => CATMAID.fetch(project.id + '/stackgroup/' + sg_id + '/info'))) | ||
tomka marked this conversation as resolved.
Show resolved
Hide resolved
|
||
) | ||
.then(sg_infos => { | ||
// Find stack groups where this stack is an (ortho)view. | ||
let ortho_sgs = sg_infos | ||
.filter(sg_info => sg_info.stacks | ||
.find(s => s.id === stack.id) | ||
.relation === 'view'); | ||
|
||
// Find if an existing manager for any of these stack groups exists. | ||
let managing_stack_id = ortho_sgs.find(sg => this.groupManagingStack.get(sg.id)); | ||
|
||
if (typeof managing_stack_id !== 'undefined') { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Out of curiosity: Is there any benefit in using this over There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since |
||
manager = this.managers.get(managing_stack_id); | ||
} else { | ||
// If no manager exists, create a new one. | ||
managing_stack_id = stack.id; | ||
manager = new LabelStackAnnotations(stack); | ||
ortho_sgs.forEach(sg => this.groupManagingStack.set(sg.id, managing_stack_id)); | ||
// Add all other stack (ortho)views in all (ortho)view groups | ||
// to this manager. | ||
ortho_sgs.forEach(sg => sg.stacks | ||
.filter(s => s.relation === 'view') | ||
.forEach(s => manager.addStackID(s.id))); | ||
this.managers.set(stack.id, manager); | ||
} | ||
|
||
return manager; | ||
}); | ||
} | ||
|
||
return Promise.resolve(manager); | ||
} | ||
} | ||
|
||
CATMAID.LabelAnnotations = new LabelAnnotations(); | ||
|
||
CATMAID.Init.on(CATMAID.Init.EVENT_PROJECT_CHANGED, CATMAID.LabelAnnotations.clear, CATMAID.LabelAnnotations); | ||
|
||
|
||
const LABEL_FILTER_KEY = 'Object Label Color Map'; | ||
|
||
const SPECIAL_LABELS = { | ||
background: 0, | ||
}; | ||
|
||
class LabelStackAnnotations { | ||
constructor( | ||
primaryStack | ||
) { | ||
this.primaryStack = primaryStack; | ||
this.stackIDs = new Set([this.primaryStack.id]); | ||
this.activeLabelID = undefined; | ||
|
||
this.specialLabels = Object.assign({}, SPECIAL_LABELS, this.primaryStack.labelMetadata()); | ||
this.stackLayerFilters = new Map(); | ||
|
||
project.on(CATMAID.Project.EVENT_STACKVIEW_ADDED, | ||
this.registerStackViewerLayers, this); | ||
CATMAID.StackViewer.on(CATMAID.StackViewer.EVENT_STACK_LAYER_ADDED, | ||
this.registerStackLayer, this); | ||
CATMAID.StackViewer.on(CATMAID.StackViewer.EVENT_STACK_LAYER_REMOVED, | ||
this.unregisterStackLayer, this); | ||
|
||
this.registerAllStackLayers(); | ||
} | ||
|
||
addStackID(stackID) { | ||
this.stackIDs.add(stackID); | ||
} | ||
|
||
unregister() { | ||
project.off(CATMAID.Project.EVENT_STACKVIEW_ADDED, | ||
this.registerStackViewerLayers, this); | ||
CATMAID.StackViewer.off(CATMAID.StackViewer.EVENT_STACK_LAYER_ADDED, | ||
this.registerStackLayer, this); | ||
CATMAID.StackViewer.off(CATMAID.StackViewer.EVENT_STACK_LAYER_REMOVED, | ||
this.unregisterStackLayer, this); | ||
this.stackLayerFilters.clear(); | ||
} | ||
|
||
activateLabel(labelID) { | ||
this.activeLabelID = labelID; | ||
|
||
for (const [stackLayer, filter] of this.stackLayerFilters.entries()) { | ||
this.updateFilter(filter); | ||
stackLayer.redraw(); | ||
stackLayer.stackViewer.layercontrol.refresh(); | ||
} | ||
} | ||
|
||
registerAllStackLayers() { | ||
for (const stackViewer of project.getStackViewers()) { | ||
this.registerStackViewerLayers(stackViewer); | ||
} | ||
} | ||
|
||
registerStackViewerLayers(stackViewer) { | ||
for (const stackLayer of stackViewer.getLayersOfType(CATMAID.StackLayer)) { | ||
this.registerStackLayer(stackLayer, stackViewer); | ||
} | ||
} | ||
|
||
registerStackLayer(stackLayer, stackViewer) { | ||
if (!this.stackIDs.has(stackLayer.stack.id)) return; | ||
|
||
let layerFilters = stackLayer.getAvailableFilters ? stackLayer.getAvailableFilters() : []; | ||
if (LABEL_FILTER_KEY in layerFilters && !this.stackLayerFilters.has(stackLayer)) { | ||
stackLayer.setBlendMode('add'); | ||
stackLayer.setInterpolationMode(CATMAID.StackLayer.INTERPOLATION_MODES.NEAREST); | ||
stackLayer.isHideable = true; | ||
let filter = new (layerFilters[LABEL_FILTER_KEY])(); | ||
this.updateFilter(filter); | ||
stackLayer.addFilter(filter); | ||
this.stackLayerFilters.set(stackLayer, filter); | ||
|
||
// TODO: coupling state refresh with stack viewer. | ||
stackLayer.redraw(); | ||
stackViewer.layercontrol.refresh(); | ||
} | ||
} | ||
|
||
unregisterStackLayer(stackLayer, stackViewer) { | ||
if (!this.stackIDs.has(stackLayer.stack.id)) return; | ||
|
||
this.stackLayerFilters.delete(stackLayer); | ||
} | ||
|
||
updateFilter(filter) { | ||
filter.pixiFilter.backgroundLabel = CATMAID.PixiLayer.Filters.int2arr( | ||
this.specialLabels.background); | ||
filter.pixiFilter.unknownLabel = typeof this.activeLabelID === 'undefined' ? | ||
[-1, -1, -1, -1] : | ||
CATMAID.PixiLayer.Filters.int2arr(this.activeLabelID); | ||
} | ||
} | ||
|
||
CATMAID.LabelStackAnnotations = LabelStackAnnotations; | ||
|
||
})(CATMAID); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is
group_relation
joined here? It seems below only the stack group ID is needed and we could basically use.values_list('id', flat=True)
to get the result list of IDs.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's vestigial from including the relation type with the group links, before I decided to just retrieve the groups explicitly anyway (thinking I might put the raw/label enum on groups). Will remove.