@cornerstonejs/tools 2.8.6 → 2.10.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/dist/esm/eventDispatchers/shared/getToolsWithActionsForKeyboardEvents.js +1 -1
- package/dist/esm/eventDispatchers/shared/getToolsWithActionsForMouseEvent.js +1 -1
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/index.js +2 -2
- package/dist/esm/stateManagement/segmentation/activeSegmentation.d.ts +1 -1
- package/dist/esm/stateManagement/segmentation/activeSegmentation.js +1 -1
- package/dist/esm/stateManagement/segmentation/index.d.ts +3 -1
- package/dist/esm/stateManagement/segmentation/index.js +3 -1
- package/dist/esm/stateManagement/segmentation/internalAddSegmentationRepresentation.js +1 -0
- package/dist/esm/stateManagement/segmentation/polySeg/Contour/utils/createAndAddContourSegmentationsFromClippedSurfaces.js +1 -1
- package/dist/esm/stateManagement/segmentation/polySeg/Labelmap/labelmapComputationStrategies.js +4 -2
- package/dist/esm/tools/annotation/RegionSegmentPlusTool.d.ts +3 -2
- package/dist/esm/tools/annotation/RegionSegmentPlusTool.js +27 -12
- package/dist/esm/tools/annotation/RegionSegmentTool.d.ts +1 -1
- package/dist/esm/tools/annotation/RegionSegmentTool.js +7 -8
- package/dist/esm/tools/annotation/SplineROITool.js +7 -1
- package/dist/esm/tools/annotation/WholeBodySegmentTool.d.ts +3 -2
- package/dist/esm/tools/annotation/WholeBodySegmentTool.js +40 -5
- package/dist/esm/tools/base/AnnotationTool.d.ts +2 -1
- package/dist/esm/tools/base/AnnotationTool.js +6 -3
- package/dist/esm/tools/base/ContourSegmentationBaseTool.d.ts +1 -0
- package/dist/esm/tools/base/ContourSegmentationBaseTool.js +1 -0
- package/dist/esm/tools/base/GrowCutBaseTool.d.ts +25 -10
- package/dist/esm/tools/base/GrowCutBaseTool.js +124 -21
- package/dist/esm/tools/displayTools/Labelmap/addLabelmapToElement.d.ts +5 -1
- package/dist/esm/tools/displayTools/Labelmap/addLabelmapToElement.js +17 -3
- package/dist/esm/tools/displayTools/Labelmap/addVolumesAsIndependentComponents.d.ts +10 -0
- package/dist/esm/tools/displayTools/Labelmap/addVolumesAsIndependentComponents.js +123 -0
- package/dist/esm/tools/displayTools/Labelmap/labelmapDisplay.d.ts +1 -0
- package/dist/esm/tools/displayTools/Labelmap/labelmapDisplay.js +17 -10
- package/dist/esm/tools/index.d.ts +3 -1
- package/dist/esm/tools/index.js +3 -1
- package/dist/esm/tools/segmentation/BrushTool.d.ts +0 -1
- package/dist/esm/tools/segmentation/LabelmapBaseTool.d.ts +5 -1
- package/dist/esm/tools/segmentation/LabelmapBaseTool.js +107 -12
- package/dist/esm/tools/segmentation/SegmentSelectTool.js +0 -1
- package/dist/esm/tools/segmentation/strategies/compositions/index.js +1 -1
- package/dist/esm/tools/segmentation/strategies/compositions/islandRemovalComposition.d.ts +5 -0
- package/dist/esm/tools/segmentation/strategies/compositions/islandRemovalComposition.js +27 -0
- package/dist/esm/tools/segmentation/strategies/compositions/labelmapStatistics.js +69 -2
- package/dist/esm/types/CalculatorTypes.d.ts +4 -0
- package/dist/esm/types/SegmentationStateTypes.d.ts +3 -1
- package/dist/esm/utilities/contourSegmentation/addContourSegmentationAnnotation.js +5 -2
- package/dist/esm/utilities/index.d.ts +3 -1
- package/dist/esm/utilities/index.js +3 -1
- package/dist/esm/utilities/planar/filterAnnotationsWithinSlice.js +2 -2
- package/dist/esm/utilities/planar/getPointInLineOfSightWithCriteria.d.ts +5 -1
- package/dist/esm/utilities/planar/getPointInLineOfSightWithCriteria.js +40 -29
- package/dist/esm/utilities/planar/index.d.ts +3 -2
- package/dist/esm/utilities/planar/index.js +3 -2
- package/dist/esm/utilities/segmentation/VolumetricCalculator.d.ts +7 -0
- package/dist/esm/utilities/segmentation/VolumetricCalculator.js +28 -0
- package/dist/esm/utilities/segmentation/growCut/runGrowCutForBoundingBox.d.ts +0 -2
- package/dist/esm/utilities/segmentation/growCut/runOneClickGrowCut.d.ts +0 -4
- package/dist/esm/utilities/segmentation/index.d.ts +2 -1
- package/dist/esm/utilities/segmentation/index.js +2 -1
- package/dist/esm/utilities/segmentation/islandRemoval.d.ts +28 -0
- package/dist/esm/utilities/segmentation/islandRemoval.js +181 -0
- package/package.json +3 -3
- package/dist/esm/tools/segmentation/strategies/compositions/islandRemoval.d.ts +0 -16
- package/dist/esm/tools/segmentation/strategies/compositions/islandRemoval.js +0 -159
- /package/dist/esm/{tools/segmentation/strategies/utils → utilities}/normalizeViewportPlane.d.ts +0 -0
- /package/dist/esm/{tools/segmentation/strategies/utils → utilities}/normalizeViewportPlane.js +0 -0
|
@@ -1,13 +1,25 @@
|
|
|
1
|
-
import { getEnabledElement, utilities as csUtils, cache, } from '@cornerstonejs/core';
|
|
1
|
+
import { getEnabledElement, utilities as csUtils, cache, getRenderingEngine, StackViewport, } from '@cornerstonejs/core';
|
|
2
2
|
import { BaseTool } from '../base';
|
|
3
3
|
import { SegmentationRepresentations } from '../../enums';
|
|
4
4
|
import { segmentIndex as segmentIndexController, state as segmentationState, activeSegmentation, } from '../../stateManagement/segmentation';
|
|
5
5
|
import { triggerSegmentationDataModified } from '../../stateManagement/segmentation/triggerSegmentationEvents';
|
|
6
6
|
import { getSVGStyleForSegment } from '../../utilities/segmentation/getSVGStyleForSegment';
|
|
7
|
+
import IslandRemoval from '../../utilities/segmentation/islandRemoval';
|
|
7
8
|
const { transformWorldToIndex, transformIndexToWorld } = csUtils;
|
|
8
9
|
class GrowCutBaseTool extends BaseTool {
|
|
10
|
+
static { this.lastGrowCutCommand = null; }
|
|
9
11
|
constructor(toolProps, defaultToolProps) {
|
|
10
|
-
|
|
12
|
+
const baseToolProps = csUtils.deepMerge({
|
|
13
|
+
configuration: {
|
|
14
|
+
positiveSeedVariance: 0.1,
|
|
15
|
+
negativeSeedVariance: 0.9,
|
|
16
|
+
shrinkExpandIncrement: 0.05,
|
|
17
|
+
islandRemoval: {
|
|
18
|
+
enabled: false,
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
}, defaultToolProps);
|
|
22
|
+
super(toolProps, baseToolProps);
|
|
11
23
|
}
|
|
12
24
|
async preMouseDownCallback(evt) {
|
|
13
25
|
const eventData = evt.detail;
|
|
@@ -16,7 +28,7 @@ class GrowCutBaseTool extends BaseTool {
|
|
|
16
28
|
const enabledElement = getEnabledElement(element);
|
|
17
29
|
const { viewport, renderingEngine } = enabledElement;
|
|
18
30
|
const { viewUp } = viewport.getCamera();
|
|
19
|
-
const { segmentationId, segmentIndex, labelmapVolumeId, referencedVolumeId, } = this.getLabelmapSegmentationData(viewport);
|
|
31
|
+
const { segmentationId, segmentIndex, labelmapVolumeId, referencedVolumeId, } = await this.getLabelmapSegmentationData(viewport);
|
|
20
32
|
if (!this._isOrthogonalView(viewport, referencedVolumeId)) {
|
|
21
33
|
throw new Error('Oblique view is not supported yet');
|
|
22
34
|
}
|
|
@@ -37,18 +49,59 @@ class GrowCutBaseTool extends BaseTool {
|
|
|
37
49
|
evt.preventDefault();
|
|
38
50
|
return true;
|
|
39
51
|
}
|
|
40
|
-
|
|
52
|
+
shrink() {
|
|
53
|
+
this._runLastCommand({
|
|
54
|
+
shrinkExpandAmount: -this.configuration.shrinkExpandIncrement,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
expand() {
|
|
58
|
+
this._runLastCommand({
|
|
59
|
+
shrinkExpandAmount: this.configuration.shrinkExpandIncrement,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
refresh() {
|
|
63
|
+
this._runLastCommand();
|
|
64
|
+
}
|
|
65
|
+
async getGrowCutLabelmap(_growCutData) {
|
|
41
66
|
throw new Error('Not implemented');
|
|
42
67
|
}
|
|
43
68
|
async runGrowCut() {
|
|
44
|
-
const {
|
|
69
|
+
const { growCutData, configuration: config } = this;
|
|
70
|
+
const { segmentation: { segmentationId, segmentIndex, labelmapVolumeId }, } = growCutData;
|
|
71
|
+
const hasSeedVarianceData = config.positiveSeedVariance !== undefined &&
|
|
72
|
+
config.negativeSeedVariance !== undefined;
|
|
45
73
|
const labelmap = cache.getVolume(labelmapVolumeId);
|
|
46
|
-
|
|
47
|
-
|
|
74
|
+
let shrinkExpandValue = 0;
|
|
75
|
+
const growCutCommand = async ({ shrinkExpandAmount = 0 } = {}) => {
|
|
76
|
+
const { positiveSeedVariance, negativeSeedVariance } = config;
|
|
77
|
+
let newPositiveSeedVariance = undefined;
|
|
78
|
+
let newNegativeSeedVariance = undefined;
|
|
79
|
+
shrinkExpandValue += shrinkExpandAmount;
|
|
80
|
+
if (hasSeedVarianceData) {
|
|
81
|
+
newPositiveSeedVariance = positiveSeedVariance + shrinkExpandValue;
|
|
82
|
+
newNegativeSeedVariance = negativeSeedVariance + shrinkExpandValue;
|
|
83
|
+
}
|
|
84
|
+
const updatedGrowCutData = Object.assign({}, growCutData, {
|
|
85
|
+
options: {
|
|
86
|
+
positiveSeedValue: segmentIndex,
|
|
87
|
+
negativeSeedValue: 255,
|
|
88
|
+
positiveSeedVariance: newPositiveSeedVariance,
|
|
89
|
+
negativeSeedVariance: newNegativeSeedVariance,
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
const growcutLabelmap = await this.getGrowCutLabelmap(updatedGrowCutData);
|
|
93
|
+
this.applyGrowCutLabelmap(segmentationId, segmentIndex, labelmap, growcutLabelmap);
|
|
94
|
+
this._removeIslands(growCutData);
|
|
95
|
+
};
|
|
96
|
+
await growCutCommand();
|
|
97
|
+
if (hasSeedVarianceData) {
|
|
98
|
+
GrowCutBaseTool.lastGrowCutCommand = growCutCommand;
|
|
99
|
+
}
|
|
100
|
+
this.growCutData = null;
|
|
48
101
|
}
|
|
49
102
|
applyGrowCutLabelmap(segmentationId, segmentIndex, targetLabelmap, sourceLabelmap) {
|
|
50
103
|
const srcLabelmapData = sourceLabelmap.voxelManager.getCompleteScalarDataArray();
|
|
51
|
-
const
|
|
104
|
+
const tgtVoxelManager = targetLabelmap.voxelManager;
|
|
52
105
|
const [srcColumns, srcRows, srcNumSlices] = sourceLabelmap.dimensions;
|
|
53
106
|
const [tgtColumns, tgtRows] = targetLabelmap.dimensions;
|
|
54
107
|
const srcPixelsPerSlice = srcColumns * srcRows;
|
|
@@ -62,29 +115,34 @@ class GrowCutBaseTool extends BaseTool {
|
|
|
62
115
|
const srcOffset = srcRow * srcColumns + srcSlice * srcPixelsPerSlice;
|
|
63
116
|
const tgtOffset = tgtColumn + tgtRow * tgtColumns + tgtSlice * tgtPixelsPerSlice;
|
|
64
117
|
for (let column = 0; column < srcColumns; column++) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
118
|
+
const labelmapValue = srcLabelmapData[srcOffset + column] === segmentIndex
|
|
119
|
+
? segmentIndex
|
|
120
|
+
: 0;
|
|
121
|
+
tgtVoxelManager.setAtIndex(tgtOffset + column, labelmapValue);
|
|
69
122
|
}
|
|
70
123
|
}
|
|
71
124
|
}
|
|
72
|
-
targetLabelmap.voxelManager.setCompleteScalarDataArray(targetLabelmapData);
|
|
73
125
|
triggerSegmentationDataModified(segmentationId);
|
|
74
126
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
});
|
|
127
|
+
_runLastCommand({ shrinkExpandAmount = 0 } = {}) {
|
|
128
|
+
const cmd = GrowCutBaseTool.lastGrowCutCommand;
|
|
129
|
+
if (cmd) {
|
|
130
|
+
cmd({ shrinkExpandAmount });
|
|
131
|
+
}
|
|
81
132
|
}
|
|
82
|
-
getLabelmapSegmentationData(viewport) {
|
|
83
|
-
const
|
|
133
|
+
async getLabelmapSegmentationData(viewport) {
|
|
134
|
+
const activeSeg = activeSegmentation.getActiveSegmentation(viewport.id);
|
|
135
|
+
if (!activeSeg) {
|
|
136
|
+
throw new Error('No active segmentation found');
|
|
137
|
+
}
|
|
138
|
+
const { segmentationId } = activeSeg;
|
|
84
139
|
const segmentIndex = segmentIndexController.getActiveSegmentIndex(segmentationId);
|
|
85
140
|
const { representationData } = segmentationState.getSegmentation(segmentationId);
|
|
86
141
|
const labelmapData = representationData[SegmentationRepresentations.Labelmap];
|
|
87
142
|
const { volumeId: labelmapVolumeId, referencedVolumeId } = labelmapData;
|
|
143
|
+
if (!labelmapVolumeId) {
|
|
144
|
+
throw new Error('Labelmap volume id not found - not implemented');
|
|
145
|
+
}
|
|
88
146
|
return {
|
|
89
147
|
segmentationId,
|
|
90
148
|
segmentIndex,
|
|
@@ -101,6 +159,51 @@ class GrowCutBaseTool extends BaseTool {
|
|
|
101
159
|
csUtils.isEqual(Math.abs(vec[1]), 1) ||
|
|
102
160
|
csUtils.isEqual(Math.abs(vec[2]), 1));
|
|
103
161
|
}
|
|
162
|
+
getRemoveIslandData(_growCutData) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
_removeIslands(growCutData) {
|
|
166
|
+
const { islandRemoval: config } = this.configuration;
|
|
167
|
+
if (!config.enabled) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const { segmentation: { segmentIndex, labelmapVolumeId }, renderingEngineId, viewportId, } = growCutData;
|
|
171
|
+
const labelmap = cache.getVolume(labelmapVolumeId);
|
|
172
|
+
const removeIslandData = this.getRemoveIslandData(growCutData);
|
|
173
|
+
if (!removeIslandData) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
const [width, height] = labelmap.dimensions;
|
|
177
|
+
const numPixelsPerSlice = width * height;
|
|
178
|
+
const { worldIslandPoints = [], islandPointIndexes = [] } = removeIslandData;
|
|
179
|
+
let ijkIslandPoints = [...(removeIslandData?.ijkIslandPoints ?? [])];
|
|
180
|
+
const renderingEngine = getRenderingEngine(renderingEngineId);
|
|
181
|
+
const viewport = renderingEngine.getViewport(viewportId);
|
|
182
|
+
const { voxelManager } = labelmap;
|
|
183
|
+
const islandRemoval = new IslandRemoval();
|
|
184
|
+
ijkIslandPoints = ijkIslandPoints.concat(worldIslandPoints.map((worldPoint) => transformWorldToIndex(labelmap.imageData, worldPoint)));
|
|
185
|
+
ijkIslandPoints = ijkIslandPoints.concat(islandPointIndexes.map((pointIndex) => {
|
|
186
|
+
const x = pointIndex % width;
|
|
187
|
+
const y = Math.floor(pointIndex / width) % height;
|
|
188
|
+
const z = Math.floor(pointIndex / numPixelsPerSlice);
|
|
189
|
+
return [x, y, z];
|
|
190
|
+
}));
|
|
191
|
+
islandRemoval.initialize(viewport, voxelManager, {
|
|
192
|
+
points: ijkIslandPoints,
|
|
193
|
+
previewSegmentIndex: segmentIndex,
|
|
194
|
+
segmentIndex,
|
|
195
|
+
});
|
|
196
|
+
islandRemoval.floodFillSegmentIsland();
|
|
197
|
+
islandRemoval.removeExternalIslands();
|
|
198
|
+
islandRemoval.removeInternalIslands();
|
|
199
|
+
}
|
|
200
|
+
getSegmentStyle({ segmentationId, viewportId, segmentIndex }) {
|
|
201
|
+
return getSVGStyleForSegment({
|
|
202
|
+
segmentationId,
|
|
203
|
+
segmentIndex,
|
|
204
|
+
viewportId,
|
|
205
|
+
});
|
|
206
|
+
}
|
|
104
207
|
}
|
|
105
208
|
GrowCutBaseTool.toolName = 'GrowCutBaseTool';
|
|
106
209
|
export default GrowCutBaseTool;
|
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
import type { LabelmapSegmentationData } from '../../../types/LabelmapTypes';
|
|
2
|
-
|
|
2
|
+
import type { LabelmapRenderingConfig } from '../../../types/SegmentationStateTypes';
|
|
3
|
+
declare function addLabelmapToElement(element: HTMLDivElement, labelMapData: LabelmapSegmentationData, segmentationId: string, config: LabelmapRenderingConfig): Promise<void | {
|
|
4
|
+
uid: string;
|
|
5
|
+
actor: any;
|
|
6
|
+
}>;
|
|
3
7
|
export default addLabelmapToElement;
|
|
@@ -3,8 +3,9 @@ import { getCurrentLabelmapImageIdForViewport } from '../../../stateManagement/s
|
|
|
3
3
|
import { getSegmentation } from '../../../stateManagement/segmentation/getSegmentation';
|
|
4
4
|
import { triggerSegmentationDataModified, triggerSegmentationModified, } from '../../../stateManagement/segmentation/triggerSegmentationEvents';
|
|
5
5
|
import { SegmentationRepresentations } from '../../../enums';
|
|
6
|
+
import { addVolumesAsIndependentComponents } from './addVolumesAsIndependentComponents';
|
|
6
7
|
const { uuidv4 } = utilities;
|
|
7
|
-
async function addLabelmapToElement(element, labelMapData, segmentationId) {
|
|
8
|
+
async function addLabelmapToElement(element, labelMapData, segmentationId, config) {
|
|
8
9
|
const enabledElement = getEnabledElement(element);
|
|
9
10
|
const { renderingEngine, viewport } = enabledElement;
|
|
10
11
|
const { id: viewportId } = viewport;
|
|
@@ -17,15 +18,28 @@ async function addLabelmapToElement(element, labelMapData, segmentationId) {
|
|
|
17
18
|
if (!cache.getVolume(volumeId)) {
|
|
18
19
|
await _handleMissingVolume(labelMapData);
|
|
19
20
|
}
|
|
21
|
+
const blendMode = config?.blendMode ?? Enums.BlendModes.MAXIMUM_INTENSITY_BLEND;
|
|
22
|
+
const useIndependentComponents = blendMode === Enums.BlendModes.LABELMAP_EDGE_PROJECTION_BLEND;
|
|
20
23
|
const volumeInputs = [
|
|
21
24
|
{
|
|
22
25
|
volumeId,
|
|
23
26
|
visibility,
|
|
24
|
-
blendMode: Enums.BlendModes.MAXIMUM_INTENSITY_BLEND,
|
|
25
27
|
representationUID: `${segmentationId}-${SegmentationRepresentations.Labelmap}`,
|
|
28
|
+
useIndependentComponents,
|
|
29
|
+
blendMode,
|
|
26
30
|
},
|
|
27
31
|
];
|
|
28
|
-
|
|
32
|
+
if (!volumeInputs[0].useIndependentComponents) {
|
|
33
|
+
await addVolumesToViewports(renderingEngine, volumeInputs, [viewportId], immediateRender, suppressEvents);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
const result = await addVolumesAsIndependentComponents({
|
|
37
|
+
viewport,
|
|
38
|
+
volumeInputs,
|
|
39
|
+
segmentationId,
|
|
40
|
+
});
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
29
43
|
}
|
|
30
44
|
else {
|
|
31
45
|
const segmentationImageId = getCurrentLabelmapImageIdForViewport(viewport.id, segmentationId);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type Types } from '@cornerstonejs/core';
|
|
2
|
+
import type vtkVolume from '@kitware/vtk.js/Rendering/Core/Volume';
|
|
3
|
+
export declare function addVolumesAsIndependentComponents({ viewport, volumeInputs, segmentationId, }: {
|
|
4
|
+
viewport: Types.IVolumeViewport;
|
|
5
|
+
volumeInputs: Types.IVolumeInput[];
|
|
6
|
+
segmentationId: string;
|
|
7
|
+
}): Promise<{
|
|
8
|
+
uid: string;
|
|
9
|
+
actor: vtkVolume;
|
|
10
|
+
}>;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { cache, Enums, convertMapperToNotSharedMapper, volumeLoader, eventTarget, createVolumeActor, } from '@cornerstonejs/core';
|
|
2
|
+
import { Events, SegmentationRepresentations } from '../../../enums';
|
|
3
|
+
import { getSegmentation } from '../../../stateManagement/segmentation/getSegmentation';
|
|
4
|
+
const internalCache = new Map();
|
|
5
|
+
const load = ({ cfun, ofun, actor }) => {
|
|
6
|
+
actor.getProperty().setRGBTransferFunction(1, cfun);
|
|
7
|
+
actor.getProperty().setScalarOpacity(1, ofun);
|
|
8
|
+
};
|
|
9
|
+
export async function addVolumesAsIndependentComponents({ viewport, volumeInputs, segmentationId, }) {
|
|
10
|
+
const defaultActor = viewport.getDefaultActor();
|
|
11
|
+
const { actor } = defaultActor;
|
|
12
|
+
const { uid, callback } = defaultActor;
|
|
13
|
+
const referenceVolumeId = viewport.getVolumeId();
|
|
14
|
+
if (internalCache.get(uid)?.added) {
|
|
15
|
+
return {
|
|
16
|
+
uid,
|
|
17
|
+
actor,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
const volumeInputArray = volumeInputs;
|
|
21
|
+
const firstImageVolume = cache.getVolume(volumeInputArray[0].volumeId);
|
|
22
|
+
if (!firstImageVolume) {
|
|
23
|
+
throw new Error(`imageVolume with id: ${firstImageVolume.volumeId} does not exist`);
|
|
24
|
+
}
|
|
25
|
+
const { volumeId } = volumeInputArray[0];
|
|
26
|
+
const segImageVolume = await volumeLoader.loadVolume(volumeId);
|
|
27
|
+
if (!segImageVolume) {
|
|
28
|
+
throw new Error(`segImageVolume with id: ${segImageVolume.volumeId} does not exist`);
|
|
29
|
+
}
|
|
30
|
+
const segVoxelManager = segImageVolume.voxelManager;
|
|
31
|
+
const { imageData: segImageData } = segImageVolume;
|
|
32
|
+
const baseVolume = cache.getVolume(referenceVolumeId);
|
|
33
|
+
const baseVoxelManager = baseVolume.voxelManager;
|
|
34
|
+
const newComp = 2;
|
|
35
|
+
const cubeData = new Float32Array(newComp * baseVolume.voxelManager.getScalarDataLength());
|
|
36
|
+
const dims = segImageData.getDimensions();
|
|
37
|
+
for (let z = 0; z < dims[2]; ++z) {
|
|
38
|
+
for (let y = 0; y < dims[1]; ++y) {
|
|
39
|
+
for (let x = 0; x < dims[0]; ++x) {
|
|
40
|
+
const iTuple = x + dims[0] * (y + dims[1] * z);
|
|
41
|
+
cubeData[iTuple * newComp + 0] = baseVoxelManager.getAtIndex(iTuple);
|
|
42
|
+
cubeData[iTuple * newComp + 1] = segVoxelManager.getAtIndex(iTuple);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
viewport.removeActors([uid]);
|
|
47
|
+
const oldMapper = actor.getMapper();
|
|
48
|
+
const mapper = convertMapperToNotSharedMapper(oldMapper);
|
|
49
|
+
actor.setMapper(mapper);
|
|
50
|
+
mapper.setBlendMode(Enums.BlendModes.LABELMAP_EDGE_PROJECTION_BLEND);
|
|
51
|
+
const arrayAgain = mapper.getInputData().getPointData().getArray(0);
|
|
52
|
+
arrayAgain.setData(cubeData);
|
|
53
|
+
arrayAgain.setNumberOfComponents(2);
|
|
54
|
+
actor.getProperty().setColorMixPreset(1);
|
|
55
|
+
actor.getProperty().setForceNearestInterpolation(1, true);
|
|
56
|
+
actor.getProperty().setIndependentComponents(true);
|
|
57
|
+
viewport.addActor({
|
|
58
|
+
actor,
|
|
59
|
+
uid,
|
|
60
|
+
callback,
|
|
61
|
+
referencedId: referenceVolumeId,
|
|
62
|
+
representationUID: `${segmentationId}-${SegmentationRepresentations.Labelmap}`,
|
|
63
|
+
});
|
|
64
|
+
internalCache.set(uid, {
|
|
65
|
+
added: true,
|
|
66
|
+
segmentationRepresentationUID: `${segmentationId}`,
|
|
67
|
+
originalBlendMode: viewport.getBlendMode(),
|
|
68
|
+
});
|
|
69
|
+
actor.set({
|
|
70
|
+
preLoad: load,
|
|
71
|
+
});
|
|
72
|
+
function onSegmentationDataModified(evt) {
|
|
73
|
+
const { segmentationId, modifiedSlicesToUse } = evt.detail;
|
|
74
|
+
const { representationData } = getSegmentation(segmentationId);
|
|
75
|
+
const { volumeId: segVolumeId } = representationData.Labelmap;
|
|
76
|
+
if (segVolumeId !== segImageVolume.volumeId) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const segmentationVolume = cache.getVolume(segVolumeId);
|
|
80
|
+
const segVoxelManager = segmentationVolume.voxelManager;
|
|
81
|
+
const array = mapper.getInputData().getPointData().getArray(0);
|
|
82
|
+
const baseData = array.getData();
|
|
83
|
+
const newComp = 2;
|
|
84
|
+
const dims = segImageData.getDimensions();
|
|
85
|
+
const slices = modifiedSlicesToUse?.length
|
|
86
|
+
? modifiedSlicesToUse
|
|
87
|
+
: Array.from({ length: dims[2] }, (_, i) => i);
|
|
88
|
+
for (const z of slices) {
|
|
89
|
+
for (let y = 0; y < dims[1]; ++y) {
|
|
90
|
+
for (let x = 0; x < dims[0]; ++x) {
|
|
91
|
+
const iTuple = x + dims[0] * (y + dims[1] * z);
|
|
92
|
+
baseData[iTuple * newComp + 1] = segVoxelManager.getAtIndex(iTuple);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
array.setData(baseData);
|
|
97
|
+
}
|
|
98
|
+
eventTarget.addEventListener(Events.SEGMENTATION_DATA_MODIFIED, onSegmentationDataModified);
|
|
99
|
+
eventTarget.addEventListener(Events.SEGMENTATION_REPRESENTATION_REMOVED, async (evt) => {
|
|
100
|
+
eventTarget.removeEventListener(Events.SEGMENTATION_DATA_MODIFIED, onSegmentationDataModified);
|
|
101
|
+
const actorEntry = viewport.getActor(uid);
|
|
102
|
+
const { element, id } = viewport;
|
|
103
|
+
viewport.removeActors([uid]);
|
|
104
|
+
const actor = await createVolumeActor({
|
|
105
|
+
volumeId: uid,
|
|
106
|
+
blendMode: Enums.BlendModes.MAXIMUM_INTENSITY_BLEND,
|
|
107
|
+
callback: ({ volumeActor }) => {
|
|
108
|
+
if (actorEntry.callback) {
|
|
109
|
+
actorEntry.callback({
|
|
110
|
+
volumeActor,
|
|
111
|
+
volumeId,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
}, element, id);
|
|
116
|
+
viewport.addActor({ actor, uid });
|
|
117
|
+
viewport.render();
|
|
118
|
+
});
|
|
119
|
+
return {
|
|
120
|
+
uid,
|
|
121
|
+
actor,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Types } from '@cornerstonejs/core';
|
|
2
2
|
import type { LabelmapRepresentation } from '../../../types/SegmentationStateTypes';
|
|
3
|
+
export declare const MAX_NUMBER_COLORS = 255;
|
|
3
4
|
declare function removeRepresentation(viewportId: string, segmentationId: string, renderImmediate?: boolean): void;
|
|
4
5
|
declare function render(viewport: Types.IStackViewport | Types.IVolumeViewport, representation: LabelmapRepresentation): Promise<void>;
|
|
5
6
|
declare const _default: {
|
|
@@ -12,7 +12,7 @@ import SegmentationRepresentations from '../../../enums/SegmentationRepresentati
|
|
|
12
12
|
import { internalGetHiddenSegmentIndices } from '../../../stateManagement/segmentation/helpers/internalGetHiddenSegmentIndices';
|
|
13
13
|
import { getActiveSegmentIndex } from '../../../stateManagement/segmentation/getActiveSegmentIndex';
|
|
14
14
|
import { getLabelmapActorEntry } from '../../../stateManagement/segmentation/helpers/getSegmentationActor';
|
|
15
|
-
const MAX_NUMBER_COLORS = 255;
|
|
15
|
+
export const MAX_NUMBER_COLORS = 255;
|
|
16
16
|
const labelMapConfigCache = new Map();
|
|
17
17
|
let polySegConversionInProgress = false;
|
|
18
18
|
function removeRepresentation(viewportId, segmentationId, renderImmediate = false) {
|
|
@@ -33,7 +33,7 @@ function removeRepresentation(viewportId, segmentationId, renderImmediate = fals
|
|
|
33
33
|
viewport.render();
|
|
34
34
|
}
|
|
35
35
|
async function render(viewport, representation) {
|
|
36
|
-
const { segmentationId } = representation;
|
|
36
|
+
const { segmentationId, config } = representation;
|
|
37
37
|
const segmentation = getSegmentation(segmentationId);
|
|
38
38
|
if (!segmentation) {
|
|
39
39
|
console.warn('No segmentation found for segmentationId: ', segmentationId);
|
|
@@ -58,7 +58,7 @@ async function render(viewport, representation) {
|
|
|
58
58
|
}
|
|
59
59
|
if (viewport instanceof VolumeViewport) {
|
|
60
60
|
if (!labelmapActorEntry) {
|
|
61
|
-
await _addLabelmapToViewport(viewport, labelmapData, segmentationId);
|
|
61
|
+
await _addLabelmapToViewport(viewport, labelmapData, segmentationId, config);
|
|
62
62
|
}
|
|
63
63
|
labelmapActorEntry = getLabelmapActorEntry(viewport.id, segmentationId);
|
|
64
64
|
}
|
|
@@ -68,7 +68,7 @@ async function render(viewport, representation) {
|
|
|
68
68
|
return;
|
|
69
69
|
}
|
|
70
70
|
if (!labelmapActorEntry) {
|
|
71
|
-
await _addLabelmapToViewport(viewport, labelmapData, segmentationId);
|
|
71
|
+
await _addLabelmapToViewport(viewport, labelmapData, segmentationId, config);
|
|
72
72
|
}
|
|
73
73
|
labelmapActorEntry = getLabelmapActorEntry(viewport.id, segmentationId);
|
|
74
74
|
}
|
|
@@ -133,11 +133,17 @@ function _setLabelmapColorAndOpacity(viewportId, labelmapActorEntry, segmentatio
|
|
|
133
133
|
}
|
|
134
134
|
}
|
|
135
135
|
}
|
|
136
|
-
const labelmapActor = labelmapActorEntry.actor;
|
|
137
|
-
labelmapActor.getProperty().setRGBTransferFunction(0, cfun);
|
|
138
136
|
ofun.setClamping(false);
|
|
139
|
-
labelmapActor.
|
|
140
|
-
labelmapActor.
|
|
137
|
+
const labelmapActor = labelmapActorEntry.actor;
|
|
138
|
+
const { preLoad } = labelmapActor.get('preLoad') || { preLoad: null };
|
|
139
|
+
if (preLoad) {
|
|
140
|
+
preLoad({ cfun, ofun, actor: labelmapActor });
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
labelmapActor.getProperty().setRGBTransferFunction(0, cfun);
|
|
144
|
+
labelmapActor.getProperty().setScalarOpacity(0, ofun);
|
|
145
|
+
labelmapActor.getProperty().setInterpolationTypeToNearest();
|
|
146
|
+
}
|
|
141
147
|
if (renderOutline) {
|
|
142
148
|
labelmapActor.getProperty().setUseLabelOutline(renderOutline);
|
|
143
149
|
labelmapActor.getProperty().setLabelOutlineOpacity(outlineOpacity);
|
|
@@ -241,8 +247,9 @@ function _needsTransferFunctionUpdate(viewportId, segmentationId, segmentIndex,
|
|
|
241
247
|
forceColorUpdate,
|
|
242
248
|
};
|
|
243
249
|
}
|
|
244
|
-
async function _addLabelmapToViewport(viewport, labelmapData, segmentationId) {
|
|
245
|
-
await addLabelmapToElement(viewport.element, labelmapData, segmentationId);
|
|
250
|
+
async function _addLabelmapToViewport(viewport, labelmapData, segmentationId, config) {
|
|
251
|
+
const result = await addLabelmapToElement(viewport.element, labelmapData, segmentationId, config);
|
|
252
|
+
return result || undefined;
|
|
246
253
|
}
|
|
247
254
|
export default {
|
|
248
255
|
render,
|
|
@@ -41,6 +41,7 @@ import AnnotationEraserTool from './AnnotationEraserTool';
|
|
|
41
41
|
import RegionSegmentTool from './annotation/RegionSegmentTool';
|
|
42
42
|
import RegionSegmentPlusTool from './annotation/RegionSegmentPlusTool';
|
|
43
43
|
import WholeBodySegmentTool from './annotation/WholeBodySegmentTool';
|
|
44
|
+
import LabelmapBaseTool from './segmentation/LabelmapBaseTool';
|
|
44
45
|
import RectangleScissorsTool from './segmentation/RectangleScissorsTool';
|
|
45
46
|
import CircleScissorsTool from './segmentation/CircleScissorsTool';
|
|
46
47
|
import SphereScissorsTool from './segmentation/SphereScissorsTool';
|
|
@@ -51,4 +52,5 @@ import BrushTool from './segmentation/BrushTool';
|
|
|
51
52
|
import PaintFillTool from './segmentation/PaintFillTool';
|
|
52
53
|
import OrientationMarkerTool from './OrientationMarkerTool';
|
|
53
54
|
import SegmentSelectTool from './segmentation/SegmentSelectTool';
|
|
54
|
-
|
|
55
|
+
import * as strategies from './segmentation/strategies';
|
|
56
|
+
export { BaseTool, AnnotationTool, AnnotationDisplayTool, PanTool, TrackballRotateTool, DragProbeTool, WindowLevelTool, WindowLevelRegionTool, StackScrollTool, PlanarRotateTool, ZoomTool, MIPJumpToClickTool, ReferenceCursors, CrosshairsTool, ReferenceLinesTool, OverlayGridTool, SegmentationIntersectionTool, BidirectionalTool, LengthTool, HeightTool, ProbeTool, RectangleROITool, EllipticalROITool, CircleROITool, ETDRSGridTool, SplineROITool, PlanarFreehandROITool, PlanarFreehandContourSegmentationTool, LivewireContourTool, LivewireContourSegmentationTool, ArrowAnnotateTool, AngleTool, CobbAngleTool, UltrasoundDirectionalTool, KeyImageTool, AnnotationEraserTool as EraserTool, RectangleScissorsTool, CircleScissorsTool, SphereScissorsTool, RectangleROIThresholdTool, RectangleROIStartEndThresholdTool, CircleROIStartEndThresholdTool, SplineContourSegmentationTool, BrushTool, MagnifyTool, AdvancedMagnifyTool, PaintFillTool, ScaleOverlayTool, OrientationMarkerTool, SculptorTool, SegmentSelectTool, VolumeRotateTool, RegionSegmentTool, RegionSegmentPlusTool, WholeBodySegmentTool, LabelmapBaseTool, strategies, };
|
package/dist/esm/tools/index.js
CHANGED
|
@@ -41,6 +41,7 @@ import AnnotationEraserTool from './AnnotationEraserTool';
|
|
|
41
41
|
import RegionSegmentTool from './annotation/RegionSegmentTool';
|
|
42
42
|
import RegionSegmentPlusTool from './annotation/RegionSegmentPlusTool';
|
|
43
43
|
import WholeBodySegmentTool from './annotation/WholeBodySegmentTool';
|
|
44
|
+
import LabelmapBaseTool from './segmentation/LabelmapBaseTool';
|
|
44
45
|
import RectangleScissorsTool from './segmentation/RectangleScissorsTool';
|
|
45
46
|
import CircleScissorsTool from './segmentation/CircleScissorsTool';
|
|
46
47
|
import SphereScissorsTool from './segmentation/SphereScissorsTool';
|
|
@@ -51,4 +52,5 @@ import BrushTool from './segmentation/BrushTool';
|
|
|
51
52
|
import PaintFillTool from './segmentation/PaintFillTool';
|
|
52
53
|
import OrientationMarkerTool from './OrientationMarkerTool';
|
|
53
54
|
import SegmentSelectTool from './segmentation/SegmentSelectTool';
|
|
54
|
-
|
|
55
|
+
import * as strategies from './segmentation/strategies';
|
|
56
|
+
export { BaseTool, AnnotationTool, AnnotationDisplayTool, PanTool, TrackballRotateTool, DragProbeTool, WindowLevelTool, WindowLevelRegionTool, StackScrollTool, PlanarRotateTool, ZoomTool, MIPJumpToClickTool, ReferenceCursors, CrosshairsTool, ReferenceLinesTool, OverlayGridTool, SegmentationIntersectionTool, BidirectionalTool, LengthTool, HeightTool, ProbeTool, RectangleROITool, EllipticalROITool, CircleROITool, ETDRSGridTool, SplineROITool, PlanarFreehandROITool, PlanarFreehandContourSegmentationTool, LivewireContourTool, LivewireContourSegmentationTool, ArrowAnnotateTool, AngleTool, CobbAngleTool, UltrasoundDirectionalTool, KeyImageTool, AnnotationEraserTool as EraserTool, RectangleScissorsTool, CircleScissorsTool, SphereScissorsTool, RectangleROIThresholdTool, RectangleROIStartEndThresholdTool, CircleROIStartEndThresholdTool, SplineContourSegmentationTool, BrushTool, MagnifyTool, AdvancedMagnifyTool, PaintFillTool, ScaleOverlayTool, OrientationMarkerTool, SculptorTool, SegmentSelectTool, VolumeRotateTool, RegionSegmentTool, RegionSegmentPlusTool, WholeBodySegmentTool, LabelmapBaseTool, strategies, };
|
|
@@ -3,7 +3,6 @@ import type { PublicToolProps, ToolProps, EventTypes, SVGDrawingHelper } from '.
|
|
|
3
3
|
import LabelmapBaseTool from './LabelmapBaseTool';
|
|
4
4
|
declare class BrushTool extends LabelmapBaseTool {
|
|
5
5
|
static toolName: any;
|
|
6
|
-
prg: any;
|
|
7
6
|
constructor(toolProps?: PublicToolProps, defaultToolProps?: ToolProps);
|
|
8
7
|
onSetToolPassive: (evt: any) => void;
|
|
9
8
|
onSetToolEnabled: () => void;
|
|
@@ -31,8 +31,9 @@ export default class LabelmapBaseTool extends BaseTool {
|
|
|
31
31
|
centerCanvas?: Array<number>;
|
|
32
32
|
viewport: Types.IViewport;
|
|
33
33
|
};
|
|
34
|
-
|
|
34
|
+
static previewData?: PreviewData;
|
|
35
35
|
constructor(toolProps: any, defaultToolProps: any);
|
|
36
|
+
protected get _previewData(): PreviewData;
|
|
36
37
|
createMemo(segmentId: string, segmentationVoxelManager: any, preview: any): LabelmapMemo.LabelmapMemo;
|
|
37
38
|
createEditData(element: any): {
|
|
38
39
|
volumeId: string;
|
|
@@ -157,4 +158,7 @@ export default class LabelmapBaseTool extends BaseTool {
|
|
|
157
158
|
}): unknown;
|
|
158
159
|
rejectPreview(element?: HTMLDivElement): void;
|
|
159
160
|
acceptPreview(element?: HTMLDivElement): void;
|
|
161
|
+
static viewportContoursToLabelmap(viewport: Types.IViewport, options?: {
|
|
162
|
+
removeContours: boolean;
|
|
163
|
+
}): void;
|
|
160
164
|
}
|