-
Notifications
You must be signed in to change notification settings - Fork 24
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
Colors for mappings #2965
Merged
+221
−56
Merged
Colors for mappings #2965
Changes from 9 commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
dbfbaad
make it possible to specify custom colors for mappings (#2173)
daniel-wer bcfc991
fix shader code when mappings are not supported, add test (#2173)
daniel-wer 5c7142d
Merge branch 'master' of github.com:scalableminds/webknossos into col…
daniel-wer a17979c
remove volume tracing assertion from getVolumeTracingLayerName api fu…
daniel-wer 3119d77
fix flow, linter
daniel-wer 6651975
Merge branch 'master' of github.com:scalableminds/webknossos into col…
daniel-wer 23ba04e
improve usability of colors for mappings, first color specifies the c…
daniel-wer 3a02e8d
Merge branch 'master' of github.com:scalableminds/webknossos into col…
daniel-wer f2e6ddc
fix mapping info view if custom colors are used, but missing -> make …
daniel-wer e416287
Merge branch 'master' of github.com:scalableminds/webknossos into col…
daniel-wer 537969b
apply PR feedback, default color for mapping with colors, add changelog
daniel-wer e7171ae
Merge branch 'master' into colors-for-mappings
daniel-wer 983b9db
Merge branch 'master' into colors-for-mappings
daniel-wer 47edf2f
Merge branch 'master' into colors-for-mappings
daniel-wer File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,12 +15,13 @@ import UpdatableTexture from "libs/UpdatableTexture"; | |
import { getRenderer } from "oxalis/controller/renderer"; | ||
import { listenToStoreProperty } from "oxalis/model/helpers/listener_helpers"; | ||
import messages from "messages"; | ||
import { getMappings } from "oxalis/model/accessors/dataset_accessor"; | ||
import { getMappings, getLayerByName } from "oxalis/model/accessors/dataset_accessor"; | ||
import type { MappingType } from "oxalis/store"; | ||
import type { APIMappingType } from "admin/api_flow_types"; | ||
import type DataLayer from "oxalis/model/data_layer"; | ||
|
||
export const MAPPING_TEXTURE_WIDTH = 4096; | ||
export const MAPPING_COLOR_TEXTURE_WIDTH = 16; | ||
|
||
type APIMappingsType = { [string]: APIMappingType }; | ||
|
||
|
@@ -41,20 +42,21 @@ export function setupGlobalMappingsObject(segmentationLayer: DataLayer) { | |
|
||
class Mappings { | ||
baseUrl: string; | ||
availableMappings: Array<string>; | ||
layerName: string; | ||
mappingTexture: UpdatableTexture; | ||
mappingLookupTexture: UpdatableTexture; | ||
mappingColorTexture: UpdatableTexture; | ||
|
||
constructor(layerName: string) { | ||
const { dataset } = Store.getState(); | ||
const datasetName = dataset.name; | ||
const dataStoreUrl = dataset.dataStore.url; | ||
this.layerName = layerName; | ||
this.baseUrl = `${dataStoreUrl}/data/datasets/${datasetName}/layers/${layerName}/mappings/`; | ||
this.availableMappings = getMappings(dataset, layerName); | ||
} | ||
|
||
getMappingNames(): Array<string> { | ||
return this.availableMappings; | ||
return getMappings(Store.getState().dataset, this.layerName); | ||
} | ||
|
||
async activateMapping(mappingName: ?string) { | ||
|
@@ -63,8 +65,12 @@ class Mappings { | |
} else { | ||
const fetchedMappings = {}; | ||
await this.fetchMappings(mappingName, fetchedMappings); | ||
const mappingObject = this.buildMappingObject(mappingName, fetchedMappings); | ||
Store.dispatch(setMappingAction(mappingObject)); | ||
const { hideUnmappedIds, colors: mappingColors } = fetchedMappings[mappingName]; | ||
// If custom colors are specified for a mapping, assign the mapped ids specifically, so that the first equivalence | ||
// class will get the first color, and so on | ||
const assignNewIds = mappingColors != null && mappingColors.length > 0; | ||
const mappingObject = this.buildMappingObject(mappingName, fetchedMappings, assignNewIds); | ||
Store.dispatch(setMappingAction(mappingObject, mappingColors, hideUnmappedIds)); | ||
} | ||
} | ||
|
||
|
@@ -92,19 +98,36 @@ class Mappings { | |
}); | ||
} | ||
|
||
buildMappingObject(mappingName: string, fetchedMappings: APIMappingsType): MappingType { | ||
getLargestSegmentId(): number { | ||
const segmentationLayer = getLayerByName(Store.getState().dataset, this.layerName); | ||
if (segmentationLayer.category !== "segmentation") { | ||
throw new Error("Mappings class must be instantiated with a segmenation layer."); | ||
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.
|
||
} | ||
return segmentationLayer.largestSegmentId; | ||
} | ||
|
||
buildMappingObject( | ||
mappingName: string, | ||
fetchedMappings: APIMappingsType, | ||
assignNewIds: boolean, | ||
): MappingType { | ||
const mappingObject: MappingType = {}; | ||
|
||
const maxId = this.getLargestSegmentId() + 1; | ||
// Initialize to the next multiple of 256 that is larger than maxId | ||
let newMappedId = Math.ceil(maxId / 256) * 256; | ||
for (const currentMappingName of this.getMappingChain(mappingName, fetchedMappings)) { | ||
const mapping = fetchedMappings[currentMappingName]; | ||
ErrorHandling.assertExists(mapping.classes, "Mappings must have been fetched at this point"); | ||
|
||
if (mapping.classes) { | ||
for (const mappingClass of mapping.classes) { | ||
const minId = _.min(mappingClass); | ||
const minId = assignNewIds ? newMappedId : _.min(mappingClass); | ||
const mappedId = mappingObject[minId] || minId; | ||
for (const id of mappingClass) { | ||
mappingObject[id] = mappedId; | ||
} | ||
newMappedId++; | ||
} | ||
} | ||
} | ||
|
@@ -125,23 +148,54 @@ class Mappings { | |
// MAPPING TEXTURES | ||
|
||
setupMappingTextures() { | ||
const renderer = getRenderer(); | ||
this.mappingTexture = createUpdatableTexture( | ||
MAPPING_TEXTURE_WIDTH, | ||
4, | ||
THREE.UnsignedByteType, | ||
getRenderer(), | ||
renderer, | ||
); | ||
this.mappingLookupTexture = createUpdatableTexture( | ||
MAPPING_TEXTURE_WIDTH, | ||
4, | ||
THREE.UnsignedByteType, | ||
getRenderer(), | ||
renderer, | ||
); | ||
// Up to 256 (16*16) custom colors can be specified for mappings | ||
this.mappingColorTexture = createUpdatableTexture( | ||
MAPPING_COLOR_TEXTURE_WIDTH, | ||
1, | ||
THREE.FloatType, | ||
renderer, | ||
); | ||
|
||
listenToStoreProperty( | ||
state => state.temporaryConfiguration.activeMapping.mapping, | ||
mapping => this.updateMappingTextures(mapping), | ||
); | ||
|
||
listenToStoreProperty( | ||
state => state.temporaryConfiguration.activeMapping.mappingColors, | ||
mappingColors => this.updateMappingColorTexture(mappingColors), | ||
); | ||
} | ||
|
||
updateMappingColorTexture(mappingColors: ?Array<number>) { | ||
mappingColors = mappingColors || []; | ||
const float32Colors = new Float32Array( | ||
MAPPING_COLOR_TEXTURE_WIDTH * MAPPING_COLOR_TEXTURE_WIDTH, | ||
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.
|
||
); | ||
const maxNumberOfColors = MAPPING_COLOR_TEXTURE_WIDTH ** 2; | ||
// Initialize the array with -1 | ||
float32Colors.fill(-1); | ||
float32Colors.set(mappingColors.slice(0, maxNumberOfColors)); | ||
this.mappingColorTexture.update( | ||
float32Colors, | ||
0, | ||
0, | ||
MAPPING_COLOR_TEXTURE_WIDTH, | ||
MAPPING_COLOR_TEXTURE_WIDTH, | ||
); | ||
} | ||
|
||
updateMappingTextures(mapping: ?MappingType): void { | ||
|
@@ -195,7 +249,7 @@ class Mappings { | |
if (this.mappingTexture == null) { | ||
this.setupMappingTextures(); | ||
} | ||
return [this.mappingTexture, this.mappingLookupTexture]; | ||
return [this.mappingTexture, this.mappingLookupTexture, this.mappingColorTexture]; | ||
} | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
I hope the increased texture uniform count will not become a problem for older hardware :/ Can you test on browserstack whether iPad still works? 🙈
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.
Mappings will be disallowed (and the textures won't be attached, see the check a couple of lines above which is not visible here) if there are not enough textures available (
Model.isMappingSupported
), so this shouldn't be a problem, right?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.
Yeah, that's right. However, the uniform is always defined in JS-land. I'm not sure whether this has implications on some systems. But probably not. We'll see :)
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.
The uniform "definition" is inside a
if (segmentationLayer != null && Model.isMappingSupported) {
check, so it should not have any implications :)