@aics/vole-core 3.14.1 → 3.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/es/FusedChannelData.js +16 -6
- package/es/types/types.d.ts +19 -8
- package/package.json +1 -1
package/es/FusedChannelData.js
CHANGED
|
@@ -7,7 +7,7 @@ const fuseShaderSrcF = "precision highp float;\nprecision highp int;\nprecision
|
|
|
7
7
|
/* babel-plugin-inline-import './constants/shaders/fuseI.frag' */
|
|
8
8
|
const fuseShaderSrcI = "precision highp float;\nprecision highp int;\nprecision highp sampler2D;\nprecision highp sampler3D;\n\n// the lut texture is a 256x1 rgba texture for each channel\nuniform sampler2D lutSampler;\n\nuniform vec2 lutMinMax;\n\n// src texture is the raw volume intensity data\nuniform isampler2D srcTexture;\n\nvoid main()\n{\n ivec2 vUv = ivec2(int(gl_FragCoord.x), int(gl_FragCoord.y));\n int intensity = texelFetch(srcTexture, vUv, 0).r;\n float ilookup = float(float(intensity) - lutMinMax.x) / float(lutMinMax.y - lutMinMax.x);\n // apply lut to intensity:\n vec4 pix = texture(lutSampler, vec2(ilookup, 0.5));\n gl_FragColor = vec4(pix.xyz*pix.w, pix.w);\n}\n";
|
|
9
9
|
/* babel-plugin-inline-import './constants/shaders/colorizeUI.frag' */
|
|
10
|
-
const colorizeSrcUI = "precision highp float;\nprecision highp int;\nprecision highp usampler2D;\nprecision highp sampler3D;\n\nuniform sampler2D featureData;\n/** Min and max feature values that define the endpoints of the color map. Values\n * outside the range will be clamped to the nearest endpoint.\n */\nuniform float featureColorRampMin;\nuniform float featureColorRampMax;\nuniform sampler2D colorRamp;\nuniform usampler2D inRangeIds;\nuniform usampler2D outlierData;\n\n
|
|
10
|
+
const colorizeSrcUI = "precision highp float;\nprecision highp int;\nprecision highp usampler2D;\nprecision highp sampler3D;\n\nuniform sampler2D featureData;\n/** Min and max feature values that define the endpoints of the color map. Values\n * outside the range will be clamped to the nearest endpoint.\n */\nuniform float featureColorRampMin;\nuniform float featureColorRampMax;\nuniform sampler2D colorRamp;\nuniform usampler2D inRangeIds;\nuniform usampler2D outlierData;\n\n/**\n * LUT mapping from the segmentation ID (raw pixel value) to the\n * global ID (index in data buffers like `featureData` and `outlierData`).\n * \n * For a given segmentation ID `segId`, the global ID is given by:\n * `segIdToGlobalId[segId - segIdOffset] - 1`.\n*/\nuniform usampler2D segIdToGlobalId;\nuniform uint segIdOffset;\n\nuniform vec3 outlineColor;\n\n/** MUST be synchronized with the DrawMode enum in ColorizeCanvas! */\nconst uint DRAW_MODE_HIDE = 0u;\nconst uint DRAW_MODE_COLOR = 1u;\nconst uint BACKGROUND_ID = 0u;\nconst uint MISSING_DATA_ID = 0xFFFFFFFFu;\n\nuniform vec3 outlierColor;\nuniform uint outlierDrawMode;\nuniform vec3 outOfRangeColor;\nuniform uint outOfRangeDrawMode;\n\nuniform uint highlightedId;\n\nuniform bool hideOutOfRange;\n\n// src texture is the raw volume intensity data\nuniform usampler2D srcTexture;\n\nvec4 getFloatFromTex(sampler2D tex, int index) {\n int width = textureSize(tex, 0).x;\n ivec2 featurePos = ivec2(index % width, index / width);\n return texelFetch(tex, featurePos, 0);\n}\nuvec4 getUintFromTex(usampler2D tex, int index) {\n int width = textureSize(tex, 0).x;\n ivec2 featurePos = ivec2(index % width, index / width);\n return texelFetch(tex, featurePos, 0);\n}\nuint getId(ivec2 uv) {\n uint rawId = texelFetch(srcTexture, uv, 0).r;\n if (rawId == 0u) {\n return BACKGROUND_ID;\n }\n uvec4 c = getUintFromTex(segIdToGlobalId, int(rawId - segIdOffset));\n // Note: IDs are offset by `1` to reserve `0` for segmentations that don't\n // have associated data. `1` MUST be subtracted from the ID when accessing\n // data buffers.\n uint globalId = c.r;\n if (globalId == 0u) {\n return MISSING_DATA_ID;\n }\n return globalId;\n}\nvec4 getColorRamp(float val) {\n float width = float(textureSize(colorRamp, 0).x);\n float range = (width - 1.0) / width;\n float adjustedVal = (0.5 / width) + (val * range);\n return texture(colorRamp, vec2(adjustedVal, 0.5));\n}\nvec4 getColorFromDrawMode(uint drawMode, vec3 defaultColor) {\n const uint DRAW_MODE_HIDE = 0u;\n vec3 backgroundColor = vec3(0.0, 0.0, 0.0);\n if (drawMode == DRAW_MODE_HIDE) {\n return vec4(backgroundColor, 0.0);\n } else {\n return vec4(defaultColor, 1.0);\n }\n}\n\nfloat getFeatureVal(uint id) {\n // Data buffer starts at 0, non-background segmentation IDs start at 1\n return getFloatFromTex(featureData, int(id) - 1).r;\n}\nuint getOutlierVal(uint id) {\n // Data buffer starts at 0, non-background segmentation IDs start at 1\n return getUintFromTex(outlierData, int(id) - 1).r;\n}\nbool getIsInRange(uint id) {\n return getUintFromTex(inRangeIds, int(id) - 1).r == 1u;\n}\nbool getIsOutlier(float featureVal, uint outlierVal) {\n return isinf(featureVal) || outlierVal != 0u;\n}\n\nvec4 getObjectColor(ivec2 sUv, float opacity) {\n // Get the segmentation id at this pixel\n uint id = getId(sUv);\n\n // A segmentation id of 0 represents background\n if (id == BACKGROUND_ID) {\n return vec4(0, 0, 0, 0);\n }\n\n // color the highlighted object. Note, `highlightedId` is a 0-based index\n // (global ID w/o offset), while `id` is a 1-based index.\n if (id - 1u == highlightedId) {\n return vec4(outlineColor, 1.0);\n }\n\n float featureVal = getFeatureVal(id);\n uint outlierVal = getOutlierVal(id);\n float normFeatureVal = (featureVal - featureColorRampMin) / (featureColorRampMax - featureColorRampMin);\n\n // Use the selected draw mode to handle out of range and outlier values;\n // otherwise color with the color ramp as usual.\n bool isInRange = getIsInRange(id);\n bool isOutlier = getIsOutlier(featureVal, outlierVal);\n bool isMissingData = (id == MISSING_DATA_ID);\n\n // Features outside the filtered/thresholded range will all be treated the same (use `outOfRangeDrawColor`).\n // Features inside the range can either be outliers or standard values, and are colored accordingly.\n vec4 color;\n if (isMissingData) { \n // TODO: Add color controls for missing data\n color = getColorFromDrawMode(outlierDrawMode, outlierColor);\n } else if (isInRange) {\n if (isOutlier) {\n color = getColorFromDrawMode(outlierDrawMode, outlierColor);\n } else {\n color = getColorRamp(normFeatureVal);\n }\n } else {\n color = getColorFromDrawMode(outOfRangeDrawMode, outOfRangeColor);\n }\n color.a *= opacity;\n return color;\n}\n\nvoid main() {\n ivec2 vUv = ivec2(int(gl_FragCoord.x), int(gl_FragCoord.y));\n gl_FragColor = getObjectColor(vUv, 1.0);\n}\n";
|
|
11
11
|
// This is the owner of the fused RGBA volume texture atlas, and the mask texture atlas.
|
|
12
12
|
// This module is responsible for updating the fused texture, given the read-only volume channel data.
|
|
13
13
|
export default class FusedChannelData {
|
|
@@ -125,7 +125,10 @@ export default class FusedChannelData {
|
|
|
125
125
|
hideOutOfRange: {
|
|
126
126
|
value: false
|
|
127
127
|
},
|
|
128
|
-
|
|
128
|
+
segIdToGlobalId: {
|
|
129
|
+
value: new DataTexture()
|
|
130
|
+
},
|
|
131
|
+
segIdOffset: {
|
|
129
132
|
value: 0
|
|
130
133
|
}
|
|
131
134
|
},
|
|
@@ -222,10 +225,17 @@ export default class FusedChannelData {
|
|
|
222
225
|
mat.uniforms.outlierDrawMode.value = feature.outlierDrawMode;
|
|
223
226
|
mat.uniforms.outOfRangeDrawMode.value = feature.outOfRangeDrawMode;
|
|
224
227
|
mat.uniforms.hideOutOfRange.value = feature.hideOutOfRange;
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
228
|
+
const time = channels[chIndex].time;
|
|
229
|
+
let globalIdLookupInfo = feature.frameToGlobalIdLookup.get(time);
|
|
230
|
+
if (!globalIdLookupInfo) {
|
|
231
|
+
console.warn(`FusedChannelData.gpuFuse: No global ID lookup info for time ${time} in channel ${chIndex}. A default lookup will be used, which may cause visual artifacts.`);
|
|
232
|
+
globalIdLookupInfo = {
|
|
233
|
+
texture: new DataTexture(Uint32Array[0]),
|
|
234
|
+
minSegId: 1
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
mat.uniforms.segIdToGlobalId.value = globalIdLookupInfo.texture;
|
|
238
|
+
mat.uniforms.segIdOffset.value = globalIdLookupInfo.minSegId;
|
|
229
239
|
} else {
|
|
230
240
|
// the lut texture is spanning only the data range of the channel, not the datatype range
|
|
231
241
|
mat.uniforms.lutMinMax.value = new Vector2(channels[chIndex].rawMin, channels[chIndex].rawMax);
|
package/es/types/types.d.ts
CHANGED
|
@@ -31,17 +31,28 @@ export interface ColorizeFeature {
|
|
|
31
31
|
idsToFeatureValue: DataTexture;
|
|
32
32
|
featureValueToColor: DataTexture;
|
|
33
33
|
/**
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
34
|
+
* Maps from a frame number to an info object used to look up the global ID
|
|
35
|
+
* from a given segmentation ID (raw pixel value) on that frame. The info
|
|
36
|
+
* object contains a texture and a minimum segmentation ID for that frame, the
|
|
37
|
+
* latter of which is used to minimize the memory footprint of the lookup
|
|
38
|
+
* table.
|
|
38
39
|
*
|
|
39
|
-
* For
|
|
40
|
-
*
|
|
40
|
+
* For a frame at time `t`, the global ID of a segmentation `segId` is given
|
|
41
|
+
* by:
|
|
42
|
+
* ```
|
|
43
|
+
* lookup[t].texture.getAt(segId - lookup[t].minSegId) - 1
|
|
44
|
+
* ```
|
|
45
|
+
* The result is `-1` if there is no global ID for that segmentation ID on
|
|
46
|
+
* that frame.
|
|
41
47
|
*
|
|
42
|
-
*
|
|
48
|
+
* The global ID can be used directly as an index into the
|
|
49
|
+
* `idsToFeatureValue`, `inRangeIds`, and `outlierData` data textures to get
|
|
50
|
+
* values for that segmentation ID.
|
|
43
51
|
*/
|
|
44
|
-
|
|
52
|
+
frameToGlobalIdLookup: Map<number, {
|
|
53
|
+
texture: DataTexture;
|
|
54
|
+
minSegId: number;
|
|
55
|
+
}>;
|
|
45
56
|
inRangeIds: DataTexture;
|
|
46
57
|
outlierData: DataTexture;
|
|
47
58
|
featureMin: number;
|