@cornerstonejs/tools 2.17.5 → 2.18.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/enums/StrategyCallbacks.d.ts +1 -0
- package/dist/esm/enums/StrategyCallbacks.js +1 -0
- package/dist/esm/tools/segmentation/BrushTool.d.ts +3 -0
- package/dist/esm/tools/segmentation/BrushTool.js +56 -0
- package/dist/esm/tools/segmentation/strategies/BrushStrategy.d.ts +5 -0
- package/dist/esm/tools/segmentation/strategies/BrushStrategy.js +10 -4
- package/dist/esm/tools/segmentation/strategies/compositions/index.d.ts +3 -0
- package/dist/esm/tools/segmentation/strategies/compositions/index.js +2 -0
- package/dist/esm/tools/segmentation/strategies/compositions/labelmapInterpolation.d.ts +6 -0
- package/dist/esm/tools/segmentation/strategies/compositions/labelmapInterpolation.js +41 -0
- package/dist/esm/tools/segmentation/strategies/fillCircle.js +2 -2
- package/dist/esm/tools/segmentation/strategies/utils/getItkImage.d.ts +2 -0
- package/dist/esm/tools/segmentation/strategies/utils/getItkImage.js +37 -0
- package/package.json +3 -3
|
@@ -5,6 +5,7 @@ declare enum StrategyCallbacks {
|
|
|
5
5
|
RejectPreview = "rejectPreview",
|
|
6
6
|
AcceptPreview = "acceptPreview",
|
|
7
7
|
Fill = "fill",
|
|
8
|
+
Interpolate = "interpolate",
|
|
8
9
|
StrategyFunction = "strategyFunction",
|
|
9
10
|
CreateIsInThreshold = "createIsInThreshold",
|
|
10
11
|
Initialize = "initialize",
|
|
@@ -6,6 +6,7 @@ var StrategyCallbacks;
|
|
|
6
6
|
StrategyCallbacks["RejectPreview"] = "rejectPreview";
|
|
7
7
|
StrategyCallbacks["AcceptPreview"] = "acceptPreview";
|
|
8
8
|
StrategyCallbacks["Fill"] = "fill";
|
|
9
|
+
StrategyCallbacks["Interpolate"] = "interpolate";
|
|
9
10
|
StrategyCallbacks["StrategyFunction"] = "strategyFunction";
|
|
10
11
|
StrategyCallbacks["CreateIsInThreshold"] = "createIsInThreshold";
|
|
11
12
|
StrategyCallbacks["Initialize"] = "initialize";
|
|
@@ -16,6 +16,9 @@ declare class BrushTool extends LabelmapBaseTool {
|
|
|
16
16
|
private _calculateCursor;
|
|
17
17
|
private _endCallback;
|
|
18
18
|
getStatistics(element: any, segmentIndices?: any): any;
|
|
19
|
+
rejectPreview(element?: HTMLDivElement): void;
|
|
20
|
+
interpolate(element: any, config: any): void;
|
|
21
|
+
acceptPreview(element?: HTMLDivElement): void;
|
|
19
22
|
private _activateDraw;
|
|
20
23
|
private _deactivateDraw;
|
|
21
24
|
invalidateBrushCursor(): void;
|
|
@@ -48,6 +48,36 @@ class BrushTool extends LabelmapBaseTool {
|
|
|
48
48
|
},
|
|
49
49
|
],
|
|
50
50
|
},
|
|
51
|
+
[StrategyCallbacks.RejectPreview]: {
|
|
52
|
+
method: StrategyCallbacks.RejectPreview,
|
|
53
|
+
bindings: [
|
|
54
|
+
{
|
|
55
|
+
key: 'Escape',
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
},
|
|
59
|
+
[StrategyCallbacks.Interpolate]: {
|
|
60
|
+
method: StrategyCallbacks.Interpolate,
|
|
61
|
+
bindings: [
|
|
62
|
+
{
|
|
63
|
+
key: 'i',
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
configuration: {
|
|
67
|
+
useBallStructuringElement: true,
|
|
68
|
+
noUseDistanceTransform: true,
|
|
69
|
+
noUseExtrapolation: true,
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
interpolateExtrapolation: {
|
|
73
|
+
method: StrategyCallbacks.Interpolate,
|
|
74
|
+
bindings: [
|
|
75
|
+
{
|
|
76
|
+
key: 'e',
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
configuration: {},
|
|
80
|
+
},
|
|
51
81
|
},
|
|
52
82
|
},
|
|
53
83
|
}) {
|
|
@@ -239,6 +269,32 @@ class BrushTool extends LabelmapBaseTool {
|
|
|
239
269
|
const stats = this.applyActiveStrategyCallback(enabledElement, this.getOperationData(element), StrategyCallbacks.GetStatistics, segmentIndices);
|
|
240
270
|
return stats;
|
|
241
271
|
}
|
|
272
|
+
rejectPreview(element = this._previewData.element) {
|
|
273
|
+
if (!element || !this._previewData.preview) {
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
const enabledElement = getEnabledElement(element);
|
|
277
|
+
this.applyActiveStrategyCallback(enabledElement, this.getOperationData(element), StrategyCallbacks.RejectPreview);
|
|
278
|
+
this._previewData.preview = null;
|
|
279
|
+
this._previewData.isDrag = false;
|
|
280
|
+
}
|
|
281
|
+
interpolate(element, config) {
|
|
282
|
+
if (!element) {
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
const enabledElement = getEnabledElement(element);
|
|
286
|
+
this._previewData.preview = this.applyActiveStrategyCallback(enabledElement, this.getOperationData(element), StrategyCallbacks.Interpolate, config.configuration);
|
|
287
|
+
this._previewData.isDrag = true;
|
|
288
|
+
}
|
|
289
|
+
acceptPreview(element = this._previewData.element) {
|
|
290
|
+
if (!element) {
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
const enabledElement = getEnabledElement(element);
|
|
294
|
+
this.applyActiveStrategyCallback(enabledElement, this.getOperationData(element), StrategyCallbacks.AcceptPreview);
|
|
295
|
+
this._previewData.isDrag = false;
|
|
296
|
+
this._previewData.preview = null;
|
|
297
|
+
}
|
|
242
298
|
invalidateBrushCursor() {
|
|
243
299
|
if (this._hoverData === undefined) {
|
|
244
300
|
return;
|
|
@@ -66,6 +66,9 @@ export default class BrushStrategy {
|
|
|
66
66
|
indices?: number | number[];
|
|
67
67
|
}) => import("../../../types").NamedStatistics;
|
|
68
68
|
};
|
|
69
|
+
labelmapInterpolation: {
|
|
70
|
+
interpolate: (operationData: InitializedOperationData, configuration: import("@itk-wasm/morphological-contour-interpolation").MorphologicalContourInterpolationOptions) => InitializedOperationData;
|
|
71
|
+
};
|
|
69
72
|
};
|
|
70
73
|
protected static childFunctions: {
|
|
71
74
|
onInteractionStart: (brushStrategy: any, func: any) => void;
|
|
@@ -73,6 +76,7 @@ export default class BrushStrategy {
|
|
|
73
76
|
fill: (brushStrategy: any, func: any) => void;
|
|
74
77
|
initialize: (brushStrategy: any, func: any) => void;
|
|
75
78
|
createIsInThreshold: (brushStrategy: any, func: any) => void;
|
|
79
|
+
interpolate: (brushStrategy: any, func: any) => void;
|
|
76
80
|
acceptPreview: (brushStrategy: any, func: any) => void;
|
|
77
81
|
rejectPreview: (brushStrategy: any, func: any) => void;
|
|
78
82
|
setValue: (brushStrategy: any, func: any) => void;
|
|
@@ -98,6 +102,7 @@ export default class BrushStrategy {
|
|
|
98
102
|
addPreview: (enabledElement: any, operationData: LabelmapToolOperationDataAny) => any;
|
|
99
103
|
acceptPreview: (enabledElement: Types.IEnabledElement, operationData: LabelmapToolOperationDataAny) => void;
|
|
100
104
|
preview: (enabledElement: Types.IEnabledElement, operationData: LabelmapToolOperationDataAny) => unknown;
|
|
105
|
+
interpolate: (enabledElement: Types.IEnabledElement, operationData: LabelmapToolOperationDataAny) => unknown;
|
|
101
106
|
setValue: (operationData: InitializedOperationData, data: any) => void;
|
|
102
107
|
createIsInThreshold: (operationData: InitializedOperationData) => any;
|
|
103
108
|
}
|
|
@@ -12,6 +12,7 @@ export default class BrushStrategy {
|
|
|
12
12
|
[StrategyCallbacks.Fill]: addListMethod(StrategyCallbacks.Fill),
|
|
13
13
|
[StrategyCallbacks.Initialize]: addListMethod(StrategyCallbacks.Initialize),
|
|
14
14
|
[StrategyCallbacks.CreateIsInThreshold]: addSingletonMethod(StrategyCallbacks.CreateIsInThreshold),
|
|
15
|
+
[StrategyCallbacks.Interpolate]: addListMethod(StrategyCallbacks.Interpolate, StrategyCallbacks.Initialize),
|
|
15
16
|
[StrategyCallbacks.AcceptPreview]: addListMethod(StrategyCallbacks.AcceptPreview, StrategyCallbacks.Initialize),
|
|
16
17
|
[StrategyCallbacks.RejectPreview]: addListMethod(StrategyCallbacks.RejectPreview, StrategyCallbacks.Initialize),
|
|
17
18
|
[StrategyCallbacks.INTERNAL_setValue]: addSingletonMethod(StrategyCallbacks.INTERNAL_setValue),
|
|
@@ -126,12 +127,17 @@ function addListMethod(name, createInitialized) {
|
|
|
126
127
|
brushStrategy[listName] ||= [];
|
|
127
128
|
brushStrategy[listName].push(func);
|
|
128
129
|
brushStrategy[name] ||= createInitialized
|
|
129
|
-
? (enabledElement, operationData) => {
|
|
130
|
+
? (enabledElement, operationData, ...args) => {
|
|
130
131
|
const initializedData = brushStrategy[createInitialized](enabledElement, operationData, name);
|
|
131
|
-
|
|
132
|
+
let returnValue;
|
|
133
|
+
brushStrategy[listName].forEach((func) => {
|
|
134
|
+
const value = func.call(brushStrategy, initializedData, ...args);
|
|
135
|
+
returnValue ||= value;
|
|
136
|
+
});
|
|
137
|
+
return returnValue;
|
|
132
138
|
}
|
|
133
|
-
: (operationData) => {
|
|
134
|
-
brushStrategy[listName].forEach((func) => func.call(brushStrategy, operationData));
|
|
139
|
+
: (operationData, ...args) => {
|
|
140
|
+
brushStrategy[listName].forEach((func) => func.call(brushStrategy, operationData, ...args));
|
|
135
141
|
};
|
|
136
142
|
};
|
|
137
143
|
}
|
|
@@ -37,5 +37,8 @@ declare const _default: {
|
|
|
37
37
|
indices?: number | number[];
|
|
38
38
|
}) => import("../../../../types").NamedStatistics;
|
|
39
39
|
};
|
|
40
|
+
labelmapInterpolation: {
|
|
41
|
+
interpolate: (operationData: import("../BrushStrategy").InitializedOperationData, configuration: import("@itk-wasm/morphological-contour-interpolation").MorphologicalContourInterpolationOptions) => import("../BrushStrategy").InitializedOperationData;
|
|
42
|
+
};
|
|
40
43
|
};
|
|
41
44
|
export default _default;
|
|
@@ -7,6 +7,7 @@ import regionFill from './regionFill';
|
|
|
7
7
|
import setValue from './setValue';
|
|
8
8
|
import threshold from './threshold';
|
|
9
9
|
import labelmapStatistics from './labelmapStatistics';
|
|
10
|
+
import labelmapInterpolation from './labelmapInterpolation';
|
|
10
11
|
export default {
|
|
11
12
|
determineSegmentIndex,
|
|
12
13
|
dynamicThreshold,
|
|
@@ -17,4 +18,5 @@ export default {
|
|
|
17
18
|
setValue,
|
|
18
19
|
threshold,
|
|
19
20
|
labelmapStatistics,
|
|
21
|
+
labelmapInterpolation,
|
|
20
22
|
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { MorphologicalContourInterpolationOptions } from '@itk-wasm/morphological-contour-interpolation';
|
|
2
|
+
import type { InitializedOperationData } from '../BrushStrategy';
|
|
3
|
+
declare const _default: {
|
|
4
|
+
interpolate: (operationData: InitializedOperationData, configuration: MorphologicalContourInterpolationOptions) => InitializedOperationData;
|
|
5
|
+
};
|
|
6
|
+
export default _default;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { morphologicalContourInterpolation } from '@itk-wasm/morphological-contour-interpolation';
|
|
2
|
+
import { utilities } from '@cornerstonejs/core';
|
|
3
|
+
import StrategyCallbacks from '../../../../enums/StrategyCallbacks';
|
|
4
|
+
import getItkImage from '../utils/getItkImage';
|
|
5
|
+
import { triggerSegmentationDataModified } from '../../../../stateManagement/segmentation/triggerSegmentationEvents';
|
|
6
|
+
import PreviewMethods from './preview';
|
|
7
|
+
const { VoxelManager } = utilities;
|
|
8
|
+
export default {
|
|
9
|
+
[StrategyCallbacks.Interpolate]: (operationData, configuration) => {
|
|
10
|
+
const { segmentationImageData, segmentIndex, preview, segmentationVoxelManager, previewSegmentIndex, previewVoxelManager, } = operationData;
|
|
11
|
+
if (preview) {
|
|
12
|
+
const callback = ({ index }) => {
|
|
13
|
+
segmentationVoxelManager.setAtIndex(index, segmentIndex);
|
|
14
|
+
};
|
|
15
|
+
previewVoxelManager.forEach(callback);
|
|
16
|
+
}
|
|
17
|
+
const inputImage = getItkImage(segmentationImageData, 'interpolation');
|
|
18
|
+
const outputPromise = morphologicalContourInterpolation(inputImage, {
|
|
19
|
+
...configuration,
|
|
20
|
+
label: segmentIndex,
|
|
21
|
+
webWorker: false,
|
|
22
|
+
});
|
|
23
|
+
outputPromise.then((value) => {
|
|
24
|
+
const { outputImage } = value;
|
|
25
|
+
const previewColors = operationData.configuration?.preview?.previewColors;
|
|
26
|
+
const assignIndex = previewSegmentIndex ?? (previewColors ? 255 : segmentIndex);
|
|
27
|
+
operationData.previewColors ||= previewColors;
|
|
28
|
+
operationData.previewSegmentIndex ||= previewColors ? 255 : undefined;
|
|
29
|
+
PreviewMethods[StrategyCallbacks.Initialize](operationData);
|
|
30
|
+
segmentationVoxelManager.forEach(({ value: originalValue, index }) => {
|
|
31
|
+
const newValue = outputImage.data[index];
|
|
32
|
+
if (newValue === originalValue) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
previewVoxelManager.setAtIndex(index, assignIndex);
|
|
36
|
+
});
|
|
37
|
+
triggerSegmentationDataModified(operationData.segmentationId, previewVoxelManager.getArrayOfModifiedSlices(), assignIndex);
|
|
38
|
+
});
|
|
39
|
+
return operationData;
|
|
40
|
+
},
|
|
41
|
+
};
|
|
@@ -61,8 +61,8 @@ function createPointInEllipse(worldInfo) {
|
|
|
61
61
|
const { precalculated } = precalculatePointInEllipse(ellipseObj, {});
|
|
62
62
|
return precalculated;
|
|
63
63
|
}
|
|
64
|
-
const CIRCLE_STRATEGY = new BrushStrategy('Circle', compositions.regionFill, compositions.setValue, initializeCircle, compositions.determineSegmentIndex, compositions.preview, compositions.labelmapStatistics);
|
|
65
|
-
const CIRCLE_THRESHOLD_STRATEGY = new BrushStrategy('CircleThreshold', compositions.regionFill, compositions.setValue, initializeCircle, compositions.determineSegmentIndex, compositions.dynamicThreshold, compositions.threshold, compositions.preview, compositions.islandRemoval, compositions.labelmapStatistics);
|
|
64
|
+
const CIRCLE_STRATEGY = new BrushStrategy('Circle', compositions.regionFill, compositions.setValue, initializeCircle, compositions.determineSegmentIndex, compositions.preview, compositions.labelmapStatistics, compositions.labelmapInterpolation);
|
|
65
|
+
const CIRCLE_THRESHOLD_STRATEGY = new BrushStrategy('CircleThreshold', compositions.regionFill, compositions.setValue, initializeCircle, compositions.determineSegmentIndex, compositions.dynamicThreshold, compositions.threshold, compositions.preview, compositions.islandRemoval, compositions.labelmapStatistics, compositions.labelmapInterpolation);
|
|
66
66
|
const fillInsideCircle = CIRCLE_STRATEGY.strategyFunction;
|
|
67
67
|
const thresholdInsideCircle = CIRCLE_THRESHOLD_STRATEGY.strategyFunction;
|
|
68
68
|
export function fillOutsideCircle() {
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Image, ImageType, IntTypes, FloatTypes, PixelTypes } from 'itk-wasm';
|
|
2
|
+
const dataTypesMap = {
|
|
3
|
+
Int8: IntTypes.Int8,
|
|
4
|
+
UInt8: IntTypes.UInt8,
|
|
5
|
+
Int16: IntTypes.Int16,
|
|
6
|
+
UInt16: IntTypes.UInt16,
|
|
7
|
+
Int32: IntTypes.Int32,
|
|
8
|
+
UInt32: IntTypes.UInt32,
|
|
9
|
+
Int64: IntTypes.Int64,
|
|
10
|
+
UInt64: IntTypes.UInt64,
|
|
11
|
+
Float32: FloatTypes.Float32,
|
|
12
|
+
Float64: FloatTypes.Float64,
|
|
13
|
+
};
|
|
14
|
+
export default function getItkImage(imageData, imageName) {
|
|
15
|
+
const { voxelManager } = imageData.get('voxelManager');
|
|
16
|
+
const { numberOfComponents } = imageData.get('numberOfComponents');
|
|
17
|
+
const scalarData = voxelManager.getCompleteScalarDataArray();
|
|
18
|
+
const dimensions = imageData.getDimensions();
|
|
19
|
+
const origin = imageData.getOrigin();
|
|
20
|
+
const spacing = imageData.getSpacing();
|
|
21
|
+
const directionArray = imageData.getDirection();
|
|
22
|
+
const direction = new Float64Array(directionArray);
|
|
23
|
+
const dataType = scalarData.constructor.name
|
|
24
|
+
.replace(/^Ui/, 'UI')
|
|
25
|
+
.replace(/Array$/, '');
|
|
26
|
+
const metadata = undefined;
|
|
27
|
+
const imageType = new ImageType(dimensions.length, dataTypesMap[dataType], PixelTypes.Scalar, numberOfComponents);
|
|
28
|
+
const image = new Image(imageType);
|
|
29
|
+
image.name = imageName;
|
|
30
|
+
image.origin = origin;
|
|
31
|
+
image.spacing = spacing;
|
|
32
|
+
image.direction = direction;
|
|
33
|
+
image.size = dimensions;
|
|
34
|
+
image.metadata = metadata;
|
|
35
|
+
image.data = scalarData;
|
|
36
|
+
return image;
|
|
37
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cornerstonejs/tools",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.18.0",
|
|
4
4
|
"description": "Cornerstone3D Tools",
|
|
5
5
|
"types": "./dist/esm/index.d.ts",
|
|
6
6
|
"module": "./dist/esm/index.js",
|
|
@@ -104,7 +104,7 @@
|
|
|
104
104
|
"canvas": "^2.11.2"
|
|
105
105
|
},
|
|
106
106
|
"peerDependencies": {
|
|
107
|
-
"@cornerstonejs/core": "^2.
|
|
107
|
+
"@cornerstonejs/core": "^2.18.0",
|
|
108
108
|
"@kitware/vtk.js": "32.9.0",
|
|
109
109
|
"@types/d3-array": "^3.0.4",
|
|
110
110
|
"@types/d3-interpolate": "^3.0.1",
|
|
@@ -123,5 +123,5 @@
|
|
|
123
123
|
"type": "individual",
|
|
124
124
|
"url": "https://ohif.org/donate"
|
|
125
125
|
},
|
|
126
|
-
"gitHead": "
|
|
126
|
+
"gitHead": "840f20730a281b4a044cc2b059c16371a80c80bc"
|
|
127
127
|
}
|