@cornerstonejs/tools 2.0.0-beta.19 → 2.0.0-beta.20
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/eventListeners/segmentation/imageChangeEventListener.js +45 -72
- package/dist/esm/eventListeners/segmentation/labelmap/onLabelmapSegmentationDataModified.js +9 -6
- package/dist/esm/stateManagement/segmentation/SegmentationStateManager.d.ts +5 -0
- package/dist/esm/stateManagement/segmentation/SegmentationStateManager.js +102 -1
- package/dist/esm/stateManagement/segmentation/config/segmentationVisibility.js +0 -2
- package/dist/esm/stateManagement/segmentation/convertStackToVolumeSegmentation.d.ts +2 -2
- package/dist/esm/stateManagement/segmentation/convertStackToVolumeSegmentation.js +7 -14
- package/dist/esm/stateManagement/segmentation/convertVolumeToStackSegmentation.d.ts +3 -3
- package/dist/esm/stateManagement/segmentation/convertVolumeToStackSegmentation.js +14 -15
- package/dist/esm/stateManagement/segmentation/polySeg/Labelmap/convertContourToLabelmap.d.ts +1 -1
- package/dist/esm/stateManagement/segmentation/polySeg/Labelmap/convertContourToLabelmap.js +3 -3
- package/dist/esm/stateManagement/segmentation/polySeg/Surface/convertLabelmapToSurface.js +2 -2
- package/dist/esm/stateManagement/segmentation/segmentationState.d.ts +3 -1
- package/dist/esm/stateManagement/segmentation/segmentationState.js +9 -1
- package/dist/esm/store/ToolGroupManager/ToolGroup.d.ts +2 -0
- package/dist/esm/store/ToolGroupManager/ToolGroup.js +10 -0
- package/dist/esm/tools/base/BaseTool.js +1 -1
- package/dist/esm/tools/displayTools/Labelmap/addLabelmapToElement.js +3 -1
- package/dist/esm/tools/displayTools/Labelmap/labelmapDisplay.js +2 -3
- package/dist/esm/tools/displayTools/Labelmap/validateLabelmap.js +3 -3
- package/dist/esm/tools/segmentation/BrushTool.d.ts +5 -5
- package/dist/esm/tools/segmentation/BrushTool.js +6 -5
- package/dist/esm/tools/segmentation/CircleScissorsTool.d.ts +1 -1
- package/dist/esm/tools/segmentation/CircleScissorsTool.js +0 -2
- package/dist/esm/tools/segmentation/PaintFillTool.js +3 -5
- package/dist/esm/tools/segmentation/RectangleScissorsTool.d.ts +1 -1
- package/dist/esm/tools/segmentation/RectangleScissorsTool.js +1 -3
- package/dist/esm/tools/segmentation/SphereScissorsTool.d.ts +1 -1
- package/dist/esm/tools/segmentation/SphereScissorsTool.js +1 -3
- package/dist/esm/tools/segmentation/strategies/compositions/dynamicThreshold.js +5 -1
- package/dist/esm/tools/segmentation/strategies/utils/getStrategyData.js +5 -3
- package/dist/esm/tools/segmentation/strategies/utils/stackVolumeCheck.js +5 -5
- package/dist/esm/types/LabelmapTypes.d.ts +2 -2
- package/dist/esm/utilities/annotationHydration.js +1 -1
- package/dist/esm/utilities/segmentation/getSegmentIndexAtLabelmapBorder.js +2 -3
- package/dist/esm/utilities/segmentation/getSegmentIndexAtWorldPoint.js +2 -4
- package/dist/esm/utilities/segmentation/getUniqueSegmentIndices.js +3 -3
- package/dist/esm/utilities/segmentation/index.d.ts +1 -2
- package/dist/esm/utilities/segmentation/index.js +1 -2
- package/dist/esm/utilities/stackPrefetch/stackContextPrefetch.js +0 -2
- package/dist/umd/index.js +1 -1
- package/dist/umd/index.js.map +1 -1
- package/package.json +3 -3
- package/dist/esm/utilities/segmentation/createImageIdReferenceMap.d.ts +0 -2
- package/dist/esm/utilities/segmentation/createImageIdReferenceMap.js +0 -7
|
@@ -3,9 +3,7 @@ import vtkImageData from '@kitware/vtk.js/Common/DataModel/ImageData';
|
|
|
3
3
|
import { BaseVolumeViewport, getEnabledElement, Enums, getEnabledElementByIds, cache, utilities, } from '@cornerstonejs/core';
|
|
4
4
|
import Representations from '../../enums/SegmentationRepresentations';
|
|
5
5
|
import * as SegmentationState from '../../stateManagement/segmentation/segmentationState';
|
|
6
|
-
import { isVolumeSegmentation } from '../../tools/segmentation/strategies/utils/stackVolumeCheck';
|
|
7
6
|
import triggerSegmentationRender from '../../utilities/segmentation/triggerSegmentationRender';
|
|
8
|
-
import triggerSegmentationRenderForViewports from '../../utilities/segmentation/triggerSegmentationRenderForViewports';
|
|
9
7
|
const enable = function (element) {
|
|
10
8
|
const { viewport } = getEnabledElement(element);
|
|
11
9
|
if (viewport instanceof BaseVolumeViewport) {
|
|
@@ -31,89 +29,59 @@ function _imageChangeEventListener(evt) {
|
|
|
31
29
|
if (!labelmapRepresentations.length) {
|
|
32
30
|
return;
|
|
33
31
|
}
|
|
32
|
+
const actors = viewport.getActors();
|
|
34
33
|
labelmapRepresentations.forEach((representation) => {
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
const labelmapData = segmentation.representationData.LABELMAP;
|
|
40
|
-
if (isVolumeSegmentation(labelmapData, viewport)) {
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
const { imageIdReferenceMap } = labelmapData;
|
|
44
|
-
segmentationRepresentations[representation.segmentationRepresentationUID] =
|
|
45
|
-
{
|
|
46
|
-
imageIdReferenceMap,
|
|
47
|
-
};
|
|
34
|
+
const { segmentationId } = representation;
|
|
35
|
+
const labelmapImageId = SegmentationState.updateSegmentationImageReferences(viewportId, segmentationId);
|
|
48
36
|
});
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
37
|
+
const allLabelmapActors = actors.filter((actor) => labelmapRepresentations.some((representation) => representation.segmentationRepresentationUID === actor.uid));
|
|
38
|
+
allLabelmapActors.forEach((actor) => {
|
|
39
|
+
const validActor = labelmapRepresentations.find((representation) => {
|
|
40
|
+
const derivedImageId = SegmentationState.getLabelmapImageIdsForViewport(viewportId, representation.segmentationId);
|
|
41
|
+
return derivedImageId === actor.referencedId;
|
|
42
|
+
});
|
|
43
|
+
if (!validActor) {
|
|
44
|
+
viewport.removeActors([actor.uid]);
|
|
55
45
|
}
|
|
56
|
-
return true;
|
|
57
46
|
});
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
47
|
+
labelmapRepresentations.forEach((representation) => {
|
|
48
|
+
const { segmentationId } = representation;
|
|
49
|
+
const currentImageId = viewport.getCurrentImageId();
|
|
50
|
+
const derivedImageId = SegmentationState.getLabelmapImageIdsForViewport(viewportId, segmentationId);
|
|
51
|
+
if (!derivedImageId) {
|
|
52
|
+
return;
|
|
62
53
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
if (!representationList.includes(actor.uid)) {
|
|
54
|
+
const derivedImage = cache.getImage(derivedImageId);
|
|
55
|
+
if (!derivedImage) {
|
|
56
|
+
console.warn('No derived image found in the cache for segmentation representation', representation);
|
|
67
57
|
return;
|
|
68
58
|
}
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
59
|
+
const segmentationActorInput = actors.find((actor) => actor.referencedId === derivedImageId);
|
|
60
|
+
if (!segmentationActorInput) {
|
|
61
|
+
const { dimensions, spacing, direction } = viewport.getImageDataMetadata(derivedImage);
|
|
62
|
+
const currentImage = cache.getImage(currentImageId) ||
|
|
63
|
+
{
|
|
64
|
+
imageId: currentImageId,
|
|
65
|
+
};
|
|
66
|
+
const { origin: currentOrigin } = viewport.getImageDataMetadata(currentImage);
|
|
67
|
+
const originToUse = currentOrigin;
|
|
78
68
|
const scalarArray = vtkDataArray.newInstance({
|
|
79
69
|
name: 'Pixels',
|
|
80
70
|
numberOfComponents: 1,
|
|
81
|
-
values:
|
|
71
|
+
values: [...derivedImage.getPixelData()],
|
|
82
72
|
});
|
|
83
73
|
const imageData = vtkImageData.newInstance();
|
|
74
|
+
imageData.setDimensions(dimensions[0], dimensions[1], 1);
|
|
75
|
+
imageData.setSpacing(spacing);
|
|
76
|
+
imageData.setDirection(direction);
|
|
77
|
+
imageData.setOrigin(originToUse);
|
|
84
78
|
imageData.getPointData().setScalars(scalarArray);
|
|
85
|
-
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
const derivedImage = cache.getImage(derivedImageId);
|
|
89
|
-
const { dimensions, spacing, direction } = viewport.getImageDataMetadata(derivedImage);
|
|
90
|
-
const currentImage = cache.getImage(currentImageId) ||
|
|
91
|
-
{
|
|
92
|
-
imageId: currentImageId,
|
|
93
|
-
};
|
|
94
|
-
const { origin: currentOrigin } = viewport.getImageDataMetadata(currentImage);
|
|
95
|
-
const originToUse = currentOrigin;
|
|
96
|
-
segmentationImageData.setOrigin(originToUse);
|
|
97
|
-
segmentationImageData.modified();
|
|
98
|
-
if (segmentationImageData.getDimensions()[0] !== dimensions[0] ||
|
|
99
|
-
segmentationImageData.getDimensions()[1] !== dimensions[1]) {
|
|
100
|
-
viewport.removeActors([actor.uid]);
|
|
79
|
+
imageData.modified();
|
|
101
80
|
viewport.addImages([
|
|
102
81
|
{
|
|
103
82
|
imageId: derivedImageId,
|
|
104
|
-
actorUID:
|
|
83
|
+
actorUID: representation.segmentationRepresentationUID,
|
|
105
84
|
callback: ({ imageActor }) => {
|
|
106
|
-
const scalarArray = vtkDataArray.newInstance({
|
|
107
|
-
name: 'Pixels',
|
|
108
|
-
numberOfComponents: 1,
|
|
109
|
-
values: [...derivedImage.getPixelData()],
|
|
110
|
-
});
|
|
111
|
-
const imageData = vtkImageData.newInstance();
|
|
112
|
-
imageData.setDimensions(dimensions[0], dimensions[1], 1);
|
|
113
|
-
imageData.setSpacing(spacing);
|
|
114
|
-
imageData.setDirection(direction);
|
|
115
|
-
imageData.setOrigin(originToUse);
|
|
116
|
-
imageData.getPointData().setScalars(scalarArray);
|
|
117
85
|
imageActor.getMapper().setInputData(imageData);
|
|
118
86
|
},
|
|
119
87
|
},
|
|
@@ -121,11 +89,16 @@ function _imageChangeEventListener(evt) {
|
|
|
121
89
|
triggerSegmentationRender();
|
|
122
90
|
return;
|
|
123
91
|
}
|
|
124
|
-
if (segmentationImageData.setDerivedImage) {
|
|
125
|
-
segmentationImageData.setDerivedImage(derivedImage);
|
|
126
|
-
}
|
|
127
92
|
else {
|
|
128
|
-
|
|
93
|
+
const segmentationImageData = segmentationActorInput.actor
|
|
94
|
+
.getMapper()
|
|
95
|
+
.getInputData();
|
|
96
|
+
if (segmentationImageData.setDerivedImage) {
|
|
97
|
+
segmentationImageData.setDerivedImage(derivedImage);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
utilities.updateVTKImageDataWithCornerstoneImage(segmentationImageData, derivedImage);
|
|
101
|
+
}
|
|
129
102
|
}
|
|
130
103
|
viewport.render();
|
|
131
104
|
if (evt.type === Enums.Events.IMAGE_RENDERED) {
|
|
@@ -2,17 +2,22 @@ import { cache, utilities as csUtils, VolumeViewport, getEnabledElementByViewpor
|
|
|
2
2
|
import * as SegmentationState from '../../../stateManagement/segmentation/segmentationState';
|
|
3
3
|
const onLabelmapSegmentationDataModified = function (evt) {
|
|
4
4
|
const { segmentationId, modifiedSlicesToUse } = evt.detail;
|
|
5
|
+
let modifiedSlices = modifiedSlicesToUse;
|
|
5
6
|
const { representationData, type } = SegmentationState.getSegmentation(segmentationId);
|
|
6
7
|
const labelmapRepresentationData = representationData[type];
|
|
8
|
+
if ('stack' in labelmapRepresentationData &&
|
|
9
|
+
'volumeId' in labelmapRepresentationData) {
|
|
10
|
+
modifiedSlices = [];
|
|
11
|
+
}
|
|
7
12
|
if ('volumeId' in labelmapRepresentationData) {
|
|
8
13
|
performVolumeLabelmapUpdate({
|
|
9
|
-
modifiedSlicesToUse,
|
|
14
|
+
modifiedSlicesToUse: modifiedSlices,
|
|
10
15
|
representationData,
|
|
11
16
|
type,
|
|
12
17
|
});
|
|
13
18
|
}
|
|
14
19
|
const viewportIds = SegmentationState.getViewportIdsWithSegmentationId(segmentationId);
|
|
15
|
-
if ('
|
|
20
|
+
if ('imageIds' in labelmapRepresentationData) {
|
|
16
21
|
performStackLabelmapUpdate({
|
|
17
22
|
viewportIds,
|
|
18
23
|
segmentationId,
|
|
@@ -29,7 +34,7 @@ function performVolumeLabelmapUpdate({ modifiedSlicesToUse, representationData,
|
|
|
29
34
|
}
|
|
30
35
|
const { imageData, vtkOpenGLTexture } = segmentationVolume;
|
|
31
36
|
let slicesToUpdate;
|
|
32
|
-
if (modifiedSlicesToUse
|
|
37
|
+
if (modifiedSlicesToUse?.length > 0) {
|
|
33
38
|
slicesToUpdate = modifiedSlicesToUse;
|
|
34
39
|
}
|
|
35
40
|
else {
|
|
@@ -60,10 +65,8 @@ function performStackLabelmapUpdate({ viewportIds, segmentationId, representatio
|
|
|
60
65
|
if (!actorEntry) {
|
|
61
66
|
return;
|
|
62
67
|
}
|
|
63
|
-
const currentImageId = viewport.getCurrentImageId();
|
|
64
68
|
const segImageData = actorEntry.actor.getMapper().getInputData();
|
|
65
|
-
const
|
|
66
|
-
const currentSegmentationImageId = imageIdReferenceMap.get(currentImageId);
|
|
69
|
+
const currentSegmentationImageId = SegmentationState.getLabelmapImageIdsForViewport(viewportId, representation.segmentationId);
|
|
67
70
|
const segmentationImage = cache.getImage(currentSegmentationImageId);
|
|
68
71
|
segImageData.modified();
|
|
69
72
|
csUtils.updateVTKImageDataWithCornerstoneImage(segImageData, segmentationImage);
|
|
@@ -3,6 +3,7 @@ import type { RepresentationConfig, SegmentRepresentationConfig, Segmentation, S
|
|
|
3
3
|
export default class SegmentationStateManager {
|
|
4
4
|
private state;
|
|
5
5
|
readonly uid: string;
|
|
6
|
+
private _stackLabelmapImageIdReferenceMap;
|
|
6
7
|
constructor(uid?: string);
|
|
7
8
|
getState(): SegmentationState;
|
|
8
9
|
getColorLUT(lutIndex: number): Types.ColorLUT | undefined;
|
|
@@ -14,6 +15,9 @@ export default class SegmentationStateManager {
|
|
|
14
15
|
getRepresentation(segmentationRepresentationUID: string): SegmentationRepresentation | undefined;
|
|
15
16
|
addRepresentation(segmentationRepresentation: SegmentationRepresentation): void;
|
|
16
17
|
addRepresentationToViewport(viewportId: string, segmentationRepresentationUID: string): void;
|
|
18
|
+
updateSegmentationImageReferences(viewportId: any, segmentationId: any): string;
|
|
19
|
+
private getLabelmapImageIds;
|
|
20
|
+
getLabelmapImageIdsForViewport(viewportId: string, segmentationId: string): string | undefined;
|
|
17
21
|
getRepresentationsForViewport(viewportId: string): SegmentationRepresentation[];
|
|
18
22
|
removeRepresentation(segmentationRepresentationUID: string): void;
|
|
19
23
|
setActiveRepresentation(viewportId: string, segmentationRepresentationUID: string): void;
|
|
@@ -32,6 +36,7 @@ export default class SegmentationStateManager {
|
|
|
32
36
|
setRepresentationVisibility(viewportId: string, segmentationRepresentationUID: string, visible: boolean): void;
|
|
33
37
|
addColorLUT(colorLUT: Types.ColorLUT, lutIndex: number): void;
|
|
34
38
|
removeColorLUT(colorLUTIndex: number): void;
|
|
39
|
+
_getStackIdForImageIds(imageIds: string[]): string;
|
|
35
40
|
}
|
|
36
41
|
declare const defaultSegmentationStateManager: SegmentationStateManager;
|
|
37
42
|
export { defaultSegmentationStateManager };
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { utilities as csUtils } from '@cornerstonejs/core';
|
|
1
|
+
import { BaseVolumeViewport, cache, utilities as csUtils, getEnabledElementByViewportId, } from '@cornerstonejs/core';
|
|
2
2
|
import { SegmentationRepresentations } from '../../enums';
|
|
3
3
|
import getDefaultContourConfig from '../../tools/displayTools/Contour/contourConfig';
|
|
4
4
|
import getDefaultLabelmapConfig from '../../tools/displayTools/Labelmap/labelmapConfig';
|
|
5
5
|
import getDefaultSurfaceConfig from '../../tools/displayTools/Surface/surfaceConfig';
|
|
6
|
+
import { convertStackToVolumeSegmentation } from './convertStackToVolumeSegmentation';
|
|
6
7
|
const newGlobalConfig = {
|
|
7
8
|
renderInactiveRepresentations: true,
|
|
8
9
|
representations: {
|
|
@@ -20,6 +21,7 @@ const initialDefaultState = {
|
|
|
20
21
|
};
|
|
21
22
|
export default class SegmentationStateManager {
|
|
22
23
|
constructor(uid) {
|
|
24
|
+
this._stackLabelmapImageIdReferenceMap = new Map();
|
|
23
25
|
if (!uid) {
|
|
24
26
|
uid = csUtils.uuidv4();
|
|
25
27
|
}
|
|
@@ -45,6 +47,13 @@ export default class SegmentationStateManager {
|
|
|
45
47
|
if (this.getSegmentation(segmentation.segmentationId)) {
|
|
46
48
|
throw new Error(`Segmentation with id ${segmentation.segmentationId} already exists`);
|
|
47
49
|
}
|
|
50
|
+
if (segmentation.representationData.LABELMAP &&
|
|
51
|
+
'volumeId' in segmentation.representationData.LABELMAP &&
|
|
52
|
+
!('imageIds' in segmentation.representationData.LABELMAP)) {
|
|
53
|
+
const imageIds = this.getLabelmapImageIds(segmentation.representationData);
|
|
54
|
+
segmentation.representationData
|
|
55
|
+
.LABELMAP.imageIds = imageIds;
|
|
56
|
+
}
|
|
48
57
|
this.state.segmentations.push(segmentation);
|
|
49
58
|
}
|
|
50
59
|
removeSegmentation(segmentationId) {
|
|
@@ -59,11 +68,98 @@ export default class SegmentationStateManager {
|
|
|
59
68
|
segmentationRepresentation;
|
|
60
69
|
}
|
|
61
70
|
addRepresentationToViewport(viewportId, segmentationRepresentationUID) {
|
|
71
|
+
const enabledElement = getEnabledElementByViewportId(viewportId);
|
|
72
|
+
if (!enabledElement) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
62
75
|
if (!this.state.viewports[viewportId]) {
|
|
63
76
|
this.state.viewports[viewportId] = {};
|
|
64
77
|
}
|
|
78
|
+
const representation = this.getRepresentation(segmentationRepresentationUID);
|
|
79
|
+
if (representation.type !== SegmentationRepresentations.Labelmap) {
|
|
80
|
+
this.setActiveRepresentation(viewportId, segmentationRepresentationUID);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const volumeViewport = enabledElement.viewport instanceof BaseVolumeViewport;
|
|
84
|
+
const segmentation = this.getSegmentation(representation.segmentationId);
|
|
85
|
+
const { representationData } = segmentation;
|
|
86
|
+
const isBaseVolumeSegmentation = 'volumeId' in representationData.LABELMAP;
|
|
87
|
+
if (!volumeViewport) {
|
|
88
|
+
if (isBaseVolumeSegmentation) {
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
this.updateSegmentationImageReferences(viewportId, segmentation.segmentationId);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
const volumeViewport = enabledElement.viewport;
|
|
96
|
+
const frameOfReferenceUID = volumeViewport.getFrameOfReferenceUID();
|
|
97
|
+
if (!isBaseVolumeSegmentation) {
|
|
98
|
+
const imageIds = this.getLabelmapImageIds(segmentation.representationData);
|
|
99
|
+
const segImage = cache.getImage(imageIds[0]);
|
|
100
|
+
if (segImage?.FrameOfReferenceUID === frameOfReferenceUID) {
|
|
101
|
+
convertStackToVolumeSegmentation(segmentation);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
}
|
|
106
|
+
}
|
|
65
107
|
this.setActiveRepresentation(viewportId, segmentationRepresentationUID);
|
|
66
108
|
}
|
|
109
|
+
updateSegmentationImageReferences(viewportId, segmentationId) {
|
|
110
|
+
const segmentation = this.getSegmentation(segmentationId);
|
|
111
|
+
if (!segmentation) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
if (!this._stackLabelmapImageIdReferenceMap.has(segmentationId)) {
|
|
115
|
+
this._stackLabelmapImageIdReferenceMap.set(segmentationId, new Map());
|
|
116
|
+
}
|
|
117
|
+
const { representationData } = segmentation;
|
|
118
|
+
const labelmapImageIds = this.getLabelmapImageIds(representationData);
|
|
119
|
+
const enabledElement = getEnabledElementByViewportId(viewportId);
|
|
120
|
+
const stackViewport = enabledElement.viewport;
|
|
121
|
+
const currentImageId = stackViewport.getCurrentImageId();
|
|
122
|
+
for (const labelmapImageId of labelmapImageIds) {
|
|
123
|
+
const viewableImageId = stackViewport.isReferenceViewable({ referencedImageId: labelmapImageId }, { asOverlay: true });
|
|
124
|
+
if (viewableImageId) {
|
|
125
|
+
this._stackLabelmapImageIdReferenceMap
|
|
126
|
+
.get(segmentationId)
|
|
127
|
+
.set(currentImageId, labelmapImageId);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return this._stackLabelmapImageIdReferenceMap
|
|
131
|
+
.get(segmentationId)
|
|
132
|
+
.get(currentImageId);
|
|
133
|
+
}
|
|
134
|
+
getLabelmapImageIds(representationData) {
|
|
135
|
+
const labelmapData = representationData.LABELMAP;
|
|
136
|
+
let labelmapImageIds;
|
|
137
|
+
if (labelmapData.imageIds) {
|
|
138
|
+
labelmapImageIds = labelmapData
|
|
139
|
+
.imageIds;
|
|
140
|
+
}
|
|
141
|
+
else if (!labelmapImageIds &&
|
|
142
|
+
labelmapData.volumeId) {
|
|
143
|
+
const volumeId = labelmapData
|
|
144
|
+
.volumeId;
|
|
145
|
+
const volume = cache.getVolume(volumeId);
|
|
146
|
+
labelmapImageIds = volume.imageIds;
|
|
147
|
+
}
|
|
148
|
+
return labelmapImageIds;
|
|
149
|
+
}
|
|
150
|
+
getLabelmapImageIdsForViewport(viewportId, segmentationId) {
|
|
151
|
+
const enabledElement = getEnabledElementByViewportId(viewportId);
|
|
152
|
+
if (!enabledElement) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
if (!this._stackLabelmapImageIdReferenceMap.has(segmentationId)) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
const stackViewport = enabledElement.viewport;
|
|
159
|
+
const currentImageId = stackViewport.getCurrentImageId();
|
|
160
|
+
const imageIdReferenceMap = this._stackLabelmapImageIdReferenceMap.get(segmentationId);
|
|
161
|
+
return imageIdReferenceMap.get(currentImageId);
|
|
162
|
+
}
|
|
67
163
|
getRepresentationsForViewport(viewportId) {
|
|
68
164
|
const viewport = this.state.viewports[viewportId];
|
|
69
165
|
if (!viewport) {
|
|
@@ -167,6 +263,11 @@ export default class SegmentationStateManager {
|
|
|
167
263
|
removeColorLUT(colorLUTIndex) {
|
|
168
264
|
delete this.state.colorLUT[colorLUTIndex];
|
|
169
265
|
}
|
|
266
|
+
_getStackIdForImageIds(imageIds) {
|
|
267
|
+
return imageIds
|
|
268
|
+
.map((imageId) => imageId.slice(-Math.round(imageId.length * 0.15)))
|
|
269
|
+
.join('_');
|
|
270
|
+
}
|
|
170
271
|
}
|
|
171
272
|
const defaultSegmentationStateManager = new SegmentationStateManager('DEFAULT');
|
|
172
273
|
export { defaultSegmentationStateManager };
|
|
@@ -2,7 +2,6 @@ import * as SegmentationState from '../../../stateManagement/segmentation/segmen
|
|
|
2
2
|
import { triggerSegmentationRepresentationModified } from '../triggerSegmentationEvents';
|
|
3
3
|
function setRepresentationVisibility(viewportId, segmentationRepresentationUID, visibility) {
|
|
4
4
|
const representation = SegmentationState.getRepresentation(segmentationRepresentationUID);
|
|
5
|
-
debugger;
|
|
6
5
|
if (!representation) {
|
|
7
6
|
return;
|
|
8
7
|
}
|
|
@@ -23,7 +22,6 @@ function setSegmentsVisibility(viewport, segmentationRepresentationUID, segmentI
|
|
|
23
22
|
}
|
|
24
23
|
function setSegmentIndexVisibility(viewportId, segmentationRepresentationUID, segmentIndex, visibility) {
|
|
25
24
|
const hiddenSegments = getSegmentsHidden(viewportId, segmentationRepresentationUID);
|
|
26
|
-
debugger;
|
|
27
25
|
visibility
|
|
28
26
|
? hiddenSegments.delete(segmentIndex)
|
|
29
27
|
: hiddenSegments.add(segmentIndex);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
declare function computeVolumeSegmentationFromStack({
|
|
2
|
-
|
|
1
|
+
declare function computeVolumeSegmentationFromStack({ imageIds, options, }: {
|
|
2
|
+
imageIds: string[];
|
|
3
3
|
options?: {
|
|
4
4
|
volumeId?: string;
|
|
5
5
|
};
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { volumeLoader, utilities as csUtils, eventTarget, cache, } from '@cornerstonejs/core';
|
|
2
|
-
import { Events
|
|
3
|
-
import addRepresentations from './addRepresentations';
|
|
2
|
+
import { Events } from '../../enums';
|
|
4
3
|
import { triggerSegmentationRender } from '../../utilities/segmentation';
|
|
5
4
|
import { getSegmentation } from './segmentationState';
|
|
6
5
|
import { triggerSegmentationDataModified } from './triggerSegmentationEvents';
|
|
7
|
-
async function computeVolumeSegmentationFromStack({
|
|
8
|
-
const segmentationImageIds =
|
|
6
|
+
async function computeVolumeSegmentationFromStack({ imageIds, options, }) {
|
|
7
|
+
const segmentationImageIds = imageIds;
|
|
9
8
|
const additionalDetails = {
|
|
10
|
-
|
|
9
|
+
imageIds,
|
|
11
10
|
};
|
|
12
11
|
const volumeId = options?.volumeId ?? csUtils.uuidv4();
|
|
13
12
|
await volumeLoader.createAndCacheVolumeFromImages(volumeId, segmentationImageIds, {
|
|
@@ -20,7 +19,7 @@ async function convertStackToVolumeSegmentation({ segmentationId, options, }) {
|
|
|
20
19
|
const data = segmentation.representationData
|
|
21
20
|
.LABELMAP;
|
|
22
21
|
const { volumeId } = await computeVolumeSegmentationFromStack({
|
|
23
|
-
|
|
22
|
+
imageIds: data.imageIds,
|
|
24
23
|
options,
|
|
25
24
|
});
|
|
26
25
|
await updateSegmentationState({
|
|
@@ -35,8 +34,8 @@ async function updateSegmentationState({ segmentationId, viewportId, volumeId, o
|
|
|
35
34
|
if (options?.removeOriginal) {
|
|
36
35
|
const data = segmentation.representationData
|
|
37
36
|
.LABELMAP;
|
|
38
|
-
const
|
|
39
|
-
|
|
37
|
+
const { imageIds } = data;
|
|
38
|
+
imageIds.forEach((imageId) => {
|
|
40
39
|
cache.removeImageLoadObject(imageId);
|
|
41
40
|
});
|
|
42
41
|
segmentation.representationData.LABELMAP = {
|
|
@@ -49,12 +48,6 @@ async function updateSegmentationState({ segmentationId, viewportId, volumeId, o
|
|
|
49
48
|
volumeId,
|
|
50
49
|
};
|
|
51
50
|
}
|
|
52
|
-
await addRepresentations(viewportId, [
|
|
53
|
-
{
|
|
54
|
-
segmentationId,
|
|
55
|
-
type: SegmentationRepresentations.Labelmap,
|
|
56
|
-
},
|
|
57
|
-
]);
|
|
58
51
|
triggerSegmentationRender(viewportId);
|
|
59
52
|
eventTarget.addEventListenerOnce(Events.SEGMENTATION_RENDERED, () => triggerSegmentationDataModified(segmentationId));
|
|
60
53
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export declare function computeStackSegmentationFromVolume({ volumeId, }: {
|
|
2
2
|
volumeId: string;
|
|
3
3
|
}): Promise<{
|
|
4
|
-
|
|
4
|
+
imageIds: string[];
|
|
5
5
|
}>;
|
|
6
6
|
export declare function convertVolumeToStackSegmentation({ segmentationId, options, }: {
|
|
7
7
|
segmentationId: string;
|
|
@@ -11,10 +11,10 @@ export declare function convertVolumeToStackSegmentation({ segmentationId, optio
|
|
|
11
11
|
removeOriginal?: boolean;
|
|
12
12
|
};
|
|
13
13
|
}): Promise<void>;
|
|
14
|
-
export declare function updateStackSegmentationState({ segmentationId, viewportId,
|
|
14
|
+
export declare function updateStackSegmentationState({ segmentationId, viewportId, imageIds, options, }: {
|
|
15
15
|
segmentationId: string;
|
|
16
16
|
viewportId: string;
|
|
17
|
-
|
|
17
|
+
imageIds: string[];
|
|
18
18
|
options?: {
|
|
19
19
|
removeOriginal?: boolean;
|
|
20
20
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { cache, eventTarget, getRenderingEngines, } from '@cornerstonejs/core';
|
|
2
2
|
import { Events, SegmentationRepresentations } from '../../enums';
|
|
3
3
|
import addRepresentations from './addRepresentations';
|
|
4
|
-
import { triggerSegmentationRender
|
|
4
|
+
import { triggerSegmentationRender } from '../../utilities/segmentation';
|
|
5
5
|
import { getSegmentation } from './segmentationState';
|
|
6
6
|
import { triggerSegmentationDataModified } from './triggerSegmentationEvents';
|
|
7
7
|
export async function computeStackSegmentationFromVolume({ volumeId, }) {
|
|
@@ -16,24 +16,24 @@ export async function computeStackSegmentationFromVolume({ volumeId, }) {
|
|
|
16
16
|
.getVolumeViewports()
|
|
17
17
|
.find((vp) => vp.hasVolumeId(volumeId));
|
|
18
18
|
segmentationVolume.decache(!volumeUsedInOtherViewports && isAllImagesCached);
|
|
19
|
-
const
|
|
20
|
-
return {
|
|
19
|
+
const imageIds = _getLabelmapImageIdsForViewportForStackSegmentation(segmentationVolume);
|
|
20
|
+
return { imageIds };
|
|
21
21
|
}
|
|
22
22
|
export async function convertVolumeToStackSegmentation({ segmentationId, options, }) {
|
|
23
23
|
const segmentation = getSegmentation(segmentationId);
|
|
24
24
|
const data = segmentation.representationData
|
|
25
25
|
.LABELMAP;
|
|
26
|
-
const {
|
|
26
|
+
const { imageIds } = await computeStackSegmentationFromVolume({
|
|
27
27
|
volumeId: data.volumeId,
|
|
28
28
|
});
|
|
29
29
|
await updateStackSegmentationState({
|
|
30
30
|
segmentationId,
|
|
31
31
|
viewportId: options.viewportId,
|
|
32
|
-
|
|
32
|
+
imageIds,
|
|
33
33
|
options,
|
|
34
34
|
});
|
|
35
35
|
}
|
|
36
|
-
export async function updateStackSegmentationState({ segmentationId, viewportId,
|
|
36
|
+
export async function updateStackSegmentationState({ segmentationId, viewportId, imageIds, options, }) {
|
|
37
37
|
const segmentation = getSegmentation(segmentationId);
|
|
38
38
|
if (options?.removeOriginal) {
|
|
39
39
|
const data = segmentation.representationData
|
|
@@ -42,13 +42,13 @@ export async function updateStackSegmentationState({ segmentationId, viewportId,
|
|
|
42
42
|
cache.removeVolumeLoadObject(data.volumeId);
|
|
43
43
|
}
|
|
44
44
|
segmentation.representationData.LABELMAP = {
|
|
45
|
-
|
|
45
|
+
imageIds,
|
|
46
46
|
};
|
|
47
47
|
}
|
|
48
48
|
else {
|
|
49
49
|
segmentation.representationData.LABELMAP = {
|
|
50
50
|
...segmentation.representationData.LABELMAP,
|
|
51
|
-
|
|
51
|
+
imageIds,
|
|
52
52
|
};
|
|
53
53
|
}
|
|
54
54
|
await addRepresentations(viewportId, [
|
|
@@ -60,15 +60,14 @@ export async function updateStackSegmentationState({ segmentationId, viewportId,
|
|
|
60
60
|
triggerSegmentationRender();
|
|
61
61
|
eventTarget.addEventListenerOnce(Events.SEGMENTATION_RENDERED, () => triggerSegmentationDataModified(segmentationId));
|
|
62
62
|
}
|
|
63
|
-
function
|
|
64
|
-
if (segmentationVolume.additionalDetails?.
|
|
65
|
-
return segmentationVolume.additionalDetails.
|
|
63
|
+
function _getLabelmapImageIdsForViewportForStackSegmentation(segmentationVolume) {
|
|
64
|
+
if (segmentationVolume.additionalDetails?.imageIds) {
|
|
65
|
+
return segmentationVolume.additionalDetails.imageIds;
|
|
66
66
|
}
|
|
67
67
|
else if (segmentationVolume.referencedImageIds?.length &&
|
|
68
68
|
!segmentationVolume.referencedImageIds[0].startsWith('derived')) {
|
|
69
|
-
const referencedImageIds = segmentationVolume.referencedImageIds;
|
|
70
69
|
const segmentationImageIds = segmentationVolume.imageIds;
|
|
71
|
-
return
|
|
70
|
+
return [...segmentationImageIds].reverse();
|
|
72
71
|
}
|
|
73
72
|
else {
|
|
74
73
|
const referencedVolumeId = segmentationVolume.referencedVolumeId;
|
|
@@ -81,7 +80,7 @@ function _getImageIdReferenceMapForStackSegmentation(segmentationVolume) {
|
|
|
81
80
|
}
|
|
82
81
|
if (referencedVolume.imageIds?.[0].startsWith('derived')) {
|
|
83
82
|
throw new Error(`Cannot convert volume segmentation that is derived from another segmentation
|
|
84
|
-
to stack segmentation yet, include the additionalDetails.
|
|
83
|
+
to stack segmentation yet, include the additionalDetails.imageIds
|
|
85
84
|
in the volume segmentation in case you need it for the conversion`);
|
|
86
85
|
}
|
|
87
86
|
const referencedImageIds = referencedVolume.imageIds;
|
|
@@ -90,6 +89,6 @@ function _getImageIdReferenceMapForStackSegmentation(segmentationVolume) {
|
|
|
90
89
|
segmentationImageIdsToUse =
|
|
91
90
|
segmentationVolume.convertToImageSlicesAndCache();
|
|
92
91
|
}
|
|
93
|
-
return
|
|
92
|
+
return [...segmentationImageIdsToUse].reverse();
|
|
94
93
|
}
|
|
95
94
|
}
|
package/dist/esm/stateManagement/segmentation/polySeg/Labelmap/convertContourToLabelmap.d.ts
CHANGED
|
@@ -3,5 +3,5 @@ export declare function convertContourToVolumeLabelmap(contourRepresentationData
|
|
|
3
3
|
volumeId: string;
|
|
4
4
|
}>;
|
|
5
5
|
export declare function convertContourToStackLabelmap(contourRepresentationData: ContourSegmentationData, options?: PolySegConversionOptions): Promise<{
|
|
6
|
-
|
|
6
|
+
imageIds: any[];
|
|
7
7
|
}>;
|
|
@@ -110,17 +110,17 @@ export async function convertContourToStackLabelmap(contourRepresentationData, o
|
|
|
110
110
|
],
|
|
111
111
|
});
|
|
112
112
|
triggerWorkerProgress(eventTarget, 1);
|
|
113
|
-
const
|
|
113
|
+
const segImageIds = [];
|
|
114
114
|
newSegmentationsScalarData.forEach(({ scalarData }, referencedImageId) => {
|
|
115
115
|
const segmentationInfo = segmentationsInfo.get(referencedImageId);
|
|
116
116
|
const { imageId: segImageId } = segmentationInfo;
|
|
117
117
|
const segImage = cache.getImage(segImageId);
|
|
118
118
|
segImage.getPixelData().set(scalarData);
|
|
119
119
|
segImage.imageFrame?.pixelData?.set(scalarData);
|
|
120
|
-
|
|
120
|
+
segImageIds.push(segImageId);
|
|
121
121
|
});
|
|
122
122
|
return {
|
|
123
|
-
|
|
123
|
+
imageIds: segImageIds,
|
|
124
124
|
};
|
|
125
125
|
}
|
|
126
126
|
function _getAnnotationMapFromSegmentation(contourRepresentationData, options = {}) {
|
|
@@ -16,9 +16,9 @@ export async function convertLabelmapToSurface(labelmapRepresentationData, segme
|
|
|
16
16
|
.volumeId;
|
|
17
17
|
}
|
|
18
18
|
else {
|
|
19
|
-
const {
|
|
19
|
+
const { imageIds } = labelmapRepresentationData;
|
|
20
20
|
({ volumeId } = await computeVolumeSegmentationFromStack({
|
|
21
|
-
|
|
21
|
+
imageIds,
|
|
22
22
|
}));
|
|
23
23
|
}
|
|
24
24
|
const volume = cache.getVolume(volumeId);
|
|
@@ -33,4 +33,6 @@ declare function getRepresentationVisibility(viewportId: string, segmentationRep
|
|
|
33
33
|
declare function setRepresentationVisibility(viewportId: string, segmentationRepresentationUID: string, visible: boolean): void;
|
|
34
34
|
declare function getActiveRepresentation(viewportId: string): SegmentationRepresentation | undefined;
|
|
35
35
|
declare function setActiveRepresentation(viewportId: string, segmentationRepresentationUID: string, suppressEvents?: boolean): void;
|
|
36
|
-
|
|
36
|
+
declare function getLabelmapImageIdsForViewport(viewportId: string, segmentationId?: string): string;
|
|
37
|
+
declare function updateSegmentationImageReferences(viewportId: string, segmentationId: string): void;
|
|
38
|
+
export { getDefaultSegmentationStateManager, getSegmentation, getSegmentations, addSegmentation, removeSegmentation, getRepresentations, getRepresentation, removeRepresentation, getGlobalConfig, setGlobalConfig, getAllSegmentsConfig, setAllSegmentsConfig, getPerSegmentConfig, setPerSegmentConfig, getRepresentationsForViewport, addRepresentationToViewport, getRepresentationsRenderingStateForViewport, addColorLUT, getColorLUT, getNextColorLUTIndex, removeColorLUT, getRepresentationsBySegmentationId, getRepresentationVisibility, setRepresentationVisibility, getViewportIdsWithSegmentationId, getActiveRepresentation, setActiveRepresentation, getLabelmapImageIdsForViewport, updateSegmentationImageReferences, };
|
|
@@ -146,4 +146,12 @@ function setActiveRepresentation(viewportId, segmentationRepresentationUID, supp
|
|
|
146
146
|
triggerSegmentationRepresentationModified(segmentationRepresentationUID);
|
|
147
147
|
}
|
|
148
148
|
}
|
|
149
|
-
|
|
149
|
+
function getLabelmapImageIdsForViewport(viewportId, segmentationId) {
|
|
150
|
+
const segmentationStateManager = getDefaultSegmentationStateManager();
|
|
151
|
+
return segmentationStateManager.getLabelmapImageIdsForViewport(viewportId, segmentationId);
|
|
152
|
+
}
|
|
153
|
+
function updateSegmentationImageReferences(viewportId, segmentationId) {
|
|
154
|
+
const segmentationStateManager = getDefaultSegmentationStateManager();
|
|
155
|
+
segmentationStateManager.updateSegmentationImageReferences(viewportId, segmentationId);
|
|
156
|
+
}
|
|
157
|
+
export { getDefaultSegmentationStateManager, getSegmentation, getSegmentations, addSegmentation, removeSegmentation, getRepresentations, getRepresentation, removeRepresentation, getGlobalConfig, setGlobalConfig, getAllSegmentsConfig, setAllSegmentsConfig, getPerSegmentConfig, setPerSegmentConfig, getRepresentationsForViewport, addRepresentationToViewport, getRepresentationsRenderingStateForViewport, addColorLUT, getColorLUT, getNextColorLUTIndex, removeColorLUT, getRepresentationsBySegmentationId, getRepresentationVisibility, setRepresentationVisibility, getViewportIdsWithSegmentationId, getActiveRepresentation, setActiveRepresentation, getLabelmapImageIdsForViewport, updateSegmentationImageReferences, };
|
|
@@ -38,6 +38,8 @@ export default class ToolGroup implements IToolGroup {
|
|
|
38
38
|
getDefaultPrimaryBindings(): IToolBinding[];
|
|
39
39
|
getToolConfiguration(toolName: string, configurationPath?: string): any;
|
|
40
40
|
getPrevActivePrimaryToolName(): string;
|
|
41
|
+
setActivePrimaryTool(toolName: string): void;
|
|
42
|
+
getCurrentActivePrimaryToolName(): string;
|
|
41
43
|
clone(newToolGroupId: any, fnToolFilter?: (toolName: string) => void): IToolGroup;
|
|
42
44
|
private _hasMousePrimaryButtonBinding;
|
|
43
45
|
private _renderViewports;
|