@cornerstonejs/tools 1.54.2 → 1.56.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/cjs/eventListeners/annotations/contourSegmentation/contourSegmentationCompleted.js +72 -74
- package/dist/cjs/eventListeners/annotations/contourSegmentation/contourSegmentationCompleted.js.map +1 -1
- package/dist/cjs/eventListeners/segmentation/imageChangeEventListener.js +15 -7
- package/dist/cjs/eventListeners/segmentation/imageChangeEventListener.js.map +1 -1
- package/dist/cjs/stateManagement/segmentation/polySeg/Labelmap/computeAndAddLabelmapRepresentation.js +1 -1
- package/dist/cjs/stateManagement/segmentation/polySeg/Labelmap/computeAndAddLabelmapRepresentation.js.map +1 -1
- package/dist/cjs/stateManagement/segmentation/polySeg/Labelmap/convertSurfaceToLabelmap.js +2 -1
- package/dist/cjs/stateManagement/segmentation/polySeg/Labelmap/convertSurfaceToLabelmap.js.map +1 -1
- package/dist/cjs/tools/annotation/LivewireContourTool.js +5 -2
- package/dist/cjs/tools/annotation/LivewireContourTool.js.map +1 -1
- package/dist/cjs/tools/annotation/PlanarFreehandROITool.js +4 -0
- package/dist/cjs/tools/annotation/PlanarFreehandROITool.js.map +1 -1
- package/dist/cjs/tools/annotation/SplineROITool.js +5 -2
- package/dist/cjs/tools/annotation/SplineROITool.js.map +1 -1
- package/dist/cjs/tools/annotation/planarFreehandROITool/drawLoop.js +2 -3
- package/dist/cjs/tools/annotation/planarFreehandROITool/drawLoop.js.map +1 -1
- package/dist/cjs/tools/base/ContourBaseTool.d.ts +8 -0
- package/dist/cjs/tools/base/ContourBaseTool.js +13 -2
- package/dist/cjs/tools/base/ContourBaseTool.js.map +1 -1
- package/dist/cjs/tools/segmentation/BrushTool.js +1 -1
- package/dist/cjs/tools/segmentation/BrushTool.js.map +1 -1
- package/dist/cjs/tools/segmentation/strategies/BrushStrategy.d.ts +3 -2
- package/dist/cjs/tools/segmentation/strategies/BrushStrategy.js +11 -4
- package/dist/cjs/tools/segmentation/strategies/BrushStrategy.js.map +1 -1
- package/dist/cjs/tools/segmentation/strategies/compositions/dynamicThreshold.js +9 -3
- package/dist/cjs/tools/segmentation/strategies/compositions/dynamicThreshold.js.map +1 -1
- package/dist/cjs/tools/segmentation/strategies/compositions/islandRemoval.js +1 -1
- package/dist/cjs/tools/segmentation/strategies/compositions/islandRemoval.js.map +1 -1
- package/dist/cjs/tools/segmentation/strategies/compositions/threshold.js +6 -2
- package/dist/cjs/tools/segmentation/strategies/compositions/threshold.js.map +1 -1
- package/dist/cjs/tools/segmentation/strategies/utils/getStrategyData.d.ts +2 -3
- package/dist/cjs/tools/segmentation/strategies/utils/getStrategyData.js +21 -6
- package/dist/cjs/tools/segmentation/strategies/utils/getStrategyData.js.map +1 -1
- package/dist/cjs/utilities/contours/updateContourPolyline.d.ts +5 -0
- package/dist/cjs/utilities/contours/updateContourPolyline.js +7 -2
- package/dist/cjs/utilities/contours/updateContourPolyline.js.map +1 -1
- package/dist/cjs/utilities/math/line/distanceToPointSquaredInfo.js.map +1 -1
- package/dist/cjs/utilities/math/polyline/decimate.d.ts +2 -0
- package/dist/cjs/utilities/math/polyline/decimate.js +73 -0
- package/dist/cjs/utilities/math/polyline/decimate.js.map +1 -0
- package/dist/cjs/utilities/math/polyline/index.d.ts +2 -1
- package/dist/cjs/utilities/math/polyline/index.js +3 -1
- package/dist/cjs/utilities/math/polyline/index.js.map +1 -1
- package/dist/cjs/utilities/pointInShapeCallback.js +3 -1
- package/dist/cjs/utilities/pointInShapeCallback.js.map +1 -1
- package/dist/cjs/utilities/segmentation/floodFill.js +16 -22
- package/dist/cjs/utilities/segmentation/floodFill.js.map +1 -1
- package/dist/cjs/utilities/segmentation/getSegmentAtLabelmapBorder.js +3 -2
- package/dist/cjs/utilities/segmentation/getSegmentAtLabelmapBorder.js.map +1 -1
- package/dist/cjs/utilities/segmentation/getSegmentAtWorldPoint.js +3 -2
- package/dist/cjs/utilities/segmentation/getSegmentAtWorldPoint.js.map +1 -1
- package/dist/esm/eventListeners/annotations/contourSegmentation/contourSegmentationCompleted.js +1 -1
- package/dist/esm/eventListeners/annotations/contourSegmentation/contourSegmentationCompleted.js.map +1 -1
- package/dist/esm/eventListeners/segmentation/imageChangeEventListener.js +16 -8
- package/dist/esm/eventListeners/segmentation/imageChangeEventListener.js.map +1 -1
- package/dist/esm/stateManagement/segmentation/polySeg/Labelmap/computeAndAddLabelmapRepresentation.js +1 -1
- package/dist/esm/stateManagement/segmentation/polySeg/Labelmap/computeAndAddLabelmapRepresentation.js.map +1 -1
- package/dist/esm/stateManagement/segmentation/polySeg/Labelmap/convertSurfaceToLabelmap.js +2 -1
- package/dist/esm/stateManagement/segmentation/polySeg/Labelmap/convertSurfaceToLabelmap.js.map +1 -1
- package/dist/esm/tools/annotation/LivewireContourTool.js +5 -2
- package/dist/esm/tools/annotation/LivewireContourTool.js.map +1 -1
- package/dist/esm/tools/annotation/PlanarFreehandROITool.js +4 -0
- package/dist/esm/tools/annotation/PlanarFreehandROITool.js.map +1 -1
- package/dist/esm/tools/annotation/SplineROITool.js +5 -2
- package/dist/esm/tools/annotation/SplineROITool.js.map +1 -1
- package/dist/esm/tools/annotation/planarFreehandROITool/drawLoop.js +2 -3
- package/dist/esm/tools/annotation/planarFreehandROITool/drawLoop.js.map +1 -1
- package/dist/esm/tools/base/ContourBaseTool.js +10 -0
- package/dist/esm/tools/base/ContourBaseTool.js.map +1 -1
- package/dist/esm/tools/segmentation/BrushTool.js +1 -1
- package/dist/esm/tools/segmentation/BrushTool.js.map +1 -1
- package/dist/esm/tools/segmentation/strategies/BrushStrategy.js +10 -3
- package/dist/esm/tools/segmentation/strategies/BrushStrategy.js.map +1 -1
- package/dist/esm/tools/segmentation/strategies/compositions/dynamicThreshold.js +9 -3
- package/dist/esm/tools/segmentation/strategies/compositions/dynamicThreshold.js.map +1 -1
- package/dist/esm/tools/segmentation/strategies/compositions/islandRemoval.js +1 -1
- package/dist/esm/tools/segmentation/strategies/compositions/islandRemoval.js.map +1 -1
- package/dist/esm/tools/segmentation/strategies/compositions/threshold.js +6 -2
- package/dist/esm/tools/segmentation/strategies/compositions/threshold.js.map +1 -1
- package/dist/esm/tools/segmentation/strategies/utils/getStrategyData.js +21 -6
- package/dist/esm/tools/segmentation/strategies/utils/getStrategyData.js.map +1 -1
- package/dist/esm/utilities/contours/updateContourPolyline.js +6 -2
- package/dist/esm/utilities/contours/updateContourPolyline.js.map +1 -1
- package/dist/esm/utilities/math/line/distanceToPointSquaredInfo.js.map +1 -1
- package/dist/esm/utilities/math/polyline/decimate.js +47 -0
- package/dist/esm/utilities/math/polyline/decimate.js.map +1 -0
- package/dist/esm/utilities/math/polyline/index.js +2 -1
- package/dist/esm/utilities/math/polyline/index.js.map +1 -1
- package/dist/esm/utilities/pointInShapeCallback.js +3 -1
- package/dist/esm/utilities/pointInShapeCallback.js.map +1 -1
- package/dist/esm/utilities/segmentation/floodFill.js +16 -22
- package/dist/esm/utilities/segmentation/floodFill.js.map +1 -1
- package/dist/esm/utilities/segmentation/getSegmentAtLabelmapBorder.js +3 -2
- package/dist/esm/utilities/segmentation/getSegmentAtLabelmapBorder.js.map +1 -1
- package/dist/esm/utilities/segmentation/getSegmentAtWorldPoint.js +3 -2
- package/dist/esm/utilities/segmentation/getSegmentAtWorldPoint.js.map +1 -1
- package/dist/types/eventListeners/segmentation/imageChangeEventListener.d.ts.map +1 -1
- package/dist/types/stateManagement/segmentation/polySeg/Labelmap/convertSurfaceToLabelmap.d.ts.map +1 -1
- package/dist/types/tools/annotation/LivewireContourTool.d.ts.map +1 -1
- package/dist/types/tools/annotation/PlanarFreehandROITool.d.ts.map +1 -1
- package/dist/types/tools/annotation/SplineROITool.d.ts.map +1 -1
- package/dist/types/tools/annotation/planarFreehandROITool/drawLoop.d.ts.map +1 -1
- package/dist/types/tools/base/ContourBaseTool.d.ts +8 -0
- package/dist/types/tools/base/ContourBaseTool.d.ts.map +1 -1
- package/dist/types/tools/segmentation/strategies/BrushStrategy.d.ts +3 -2
- package/dist/types/tools/segmentation/strategies/BrushStrategy.d.ts.map +1 -1
- package/dist/types/tools/segmentation/strategies/compositions/dynamicThreshold.d.ts.map +1 -1
- package/dist/types/tools/segmentation/strategies/compositions/islandRemoval.d.ts.map +1 -1
- package/dist/types/tools/segmentation/strategies/compositions/threshold.d.ts.map +1 -1
- package/dist/types/tools/segmentation/strategies/utils/getStrategyData.d.ts +2 -3
- package/dist/types/tools/segmentation/strategies/utils/getStrategyData.d.ts.map +1 -1
- package/dist/types/utilities/contours/updateContourPolyline.d.ts +5 -0
- package/dist/types/utilities/contours/updateContourPolyline.d.ts.map +1 -1
- package/dist/types/utilities/math/line/distanceToPointSquaredInfo.d.ts.map +1 -1
- package/dist/types/utilities/math/polyline/decimate.d.ts +3 -0
- package/dist/types/utilities/math/polyline/decimate.d.ts.map +1 -0
- package/dist/types/utilities/math/polyline/index.d.ts +2 -1
- package/dist/types/utilities/math/polyline/index.d.ts.map +1 -1
- package/dist/types/utilities/pointInShapeCallback.d.ts.map +1 -1
- package/dist/types/utilities/segmentation/floodFill.d.ts.map +1 -1
- package/dist/types/utilities/segmentation/getSegmentAtLabelmapBorder.d.ts.map +1 -1
- package/dist/types/utilities/segmentation/getSegmentAtWorldPoint.d.ts.map +1 -1
- package/dist/umd/985.index.js +1 -1
- package/dist/umd/985.index.js.map +1 -1
- package/dist/umd/index.js +1 -1
- package/dist/umd/index.js.map +1 -1
- package/package.json +7 -3
- package/src/eventListeners/annotations/contourSegmentation/contourSegmentationCompleted.ts +1 -1
- package/src/eventListeners/segmentation/imageChangeEventListener.ts +28 -13
- package/src/stateManagement/segmentation/polySeg/Labelmap/computeAndAddLabelmapRepresentation.ts +1 -1
- package/src/stateManagement/segmentation/polySeg/Labelmap/convertSurfaceToLabelmap.ts +3 -1
- package/src/tools/annotation/LivewireContourTool.ts +15 -2
- package/src/tools/annotation/PlanarFreehandROITool.ts +12 -0
- package/src/tools/annotation/SplineROITool.ts +13 -2
- package/src/tools/annotation/planarFreehandROITool/drawLoop.ts +2 -3
- package/src/tools/base/ContourBaseTool.ts +23 -0
- package/src/tools/segmentation/BrushTool.ts +1 -1
- package/src/tools/segmentation/strategies/BrushStrategy.ts +25 -4
- package/src/tools/segmentation/strategies/compositions/dynamicThreshold.ts +12 -2
- package/src/tools/segmentation/strategies/compositions/islandRemoval.ts +1 -2
- package/src/tools/segmentation/strategies/compositions/threshold.ts +8 -6
- package/src/tools/segmentation/strategies/utils/getStrategyData.ts +20 -5
- package/src/utilities/contours/updateContourPolyline.ts +23 -1
- package/src/utilities/math/line/distanceToPointSquaredInfo.ts +2 -1
- package/src/utilities/math/polyline/decimate.ts +105 -0
- package/src/utilities/math/polyline/index.ts +2 -0
- package/src/utilities/pointInShapeCallback.ts +2 -0
- package/src/utilities/segmentation/floodFill.ts +44 -31
- package/src/utilities/segmentation/getSegmentAtLabelmapBorder.ts +6 -5
- package/src/utilities/segmentation/getSegmentAtWorldPoint.ts +6 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cornerstonejs/tools",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.56.0",
|
|
4
4
|
"description": "Cornerstone3D Tools",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"types": "dist/types/index.d.ts",
|
|
@@ -29,12 +29,16 @@
|
|
|
29
29
|
"webpack:watch": "webpack --mode development --progress --watch --config ./.webpack/webpack.dev.js"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@cornerstonejs/core": "^1.
|
|
32
|
+
"@cornerstonejs/core": "^1.56.0",
|
|
33
33
|
"@icr/polyseg-wasm": "0.4.0",
|
|
34
|
+
"@types/offscreencanvas": "2019.7.3",
|
|
34
35
|
"comlink": "^4.4.1",
|
|
35
36
|
"lodash.clonedeep": "4.5.0",
|
|
36
37
|
"lodash.get": "^4.4.2"
|
|
37
38
|
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"canvas": "^2.11.2"
|
|
41
|
+
},
|
|
38
42
|
"peerDependencies": {
|
|
39
43
|
"@icr/polyseg-wasm": "0.4.0",
|
|
40
44
|
"@kitware/vtk.js": "29.3.0",
|
|
@@ -55,5 +59,5 @@
|
|
|
55
59
|
"type": "individual",
|
|
56
60
|
"url": "https://ohif.org/donate"
|
|
57
61
|
},
|
|
58
|
-
"gitHead": "
|
|
62
|
+
"gitHead": "73863e2aac88c70974cf966ca4e0eae11c1e67dc"
|
|
59
63
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import vtkDataArray from '@kitware/vtk.js/Common/Core/DataArray';
|
|
2
2
|
import vtkImageData from '@kitware/vtk.js/Common/DataModel/ImageData';
|
|
3
3
|
import {
|
|
4
|
-
|
|
4
|
+
BaseVolumeViewport,
|
|
5
5
|
getEnabledElement,
|
|
6
6
|
Enums,
|
|
7
7
|
getEnabledElementByIds,
|
|
@@ -19,7 +19,7 @@ import triggerSegmentationRender from '../../utilities/segmentation/triggerSegme
|
|
|
19
19
|
const enable = function (element: HTMLDivElement): void {
|
|
20
20
|
const { viewport } = getEnabledElement(element);
|
|
21
21
|
|
|
22
|
-
if (
|
|
22
|
+
if (viewport instanceof BaseVolumeViewport) {
|
|
23
23
|
return;
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -35,12 +35,6 @@ const enable = function (element: HTMLDivElement): void {
|
|
|
35
35
|
};
|
|
36
36
|
|
|
37
37
|
const disable = function (element: HTMLDivElement): void {
|
|
38
|
-
const { viewport } = getEnabledElement(element);
|
|
39
|
-
|
|
40
|
-
if (!(viewport instanceof StackViewport)) {
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
38
|
element.removeEventListener(
|
|
45
39
|
Enums.Events.STACK_NEW_IMAGE,
|
|
46
40
|
_imageChangeEventListener as EventListener
|
|
@@ -152,6 +146,16 @@ function _imageChangeEventListener(evt) {
|
|
|
152
146
|
// this means that this slice doesn't have a segmentation for this representation
|
|
153
147
|
// this can be a case where the segmentation was added to certain slices only
|
|
154
148
|
// so we can keep the actor but empty out the imageData
|
|
149
|
+
if (segmentationImageData.setDerivedImage) {
|
|
150
|
+
// If the image data has a set derived image, then it should be called
|
|
151
|
+
// to update any vtk or actor data associated with it. In this case, null
|
|
152
|
+
// is used to clear the data. THis allows intercepting/alternative
|
|
153
|
+
// to vtk calls. Eventually the vtk version should also use this.
|
|
154
|
+
segmentationImageData.setDerivedImage(null);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
// This is the vtk version of the clearing out the image data, and fails
|
|
158
|
+
// to work for non scalar image data.
|
|
155
159
|
const scalarArray = vtkDataArray.newInstance({
|
|
156
160
|
name: 'Pixels',
|
|
157
161
|
numberOfComponents: 1,
|
|
@@ -169,7 +173,11 @@ function _imageChangeEventListener(evt) {
|
|
|
169
173
|
const { dimensions, spacing, direction } =
|
|
170
174
|
viewport.getImageDataMetadata(derivedImage);
|
|
171
175
|
|
|
172
|
-
const currentImage =
|
|
176
|
+
const currentImage =
|
|
177
|
+
cache.getImage(currentImageId) ||
|
|
178
|
+
({
|
|
179
|
+
imageId: currentImageId,
|
|
180
|
+
} as Types.IImage);
|
|
173
181
|
const { origin: currentOrigin } =
|
|
174
182
|
viewport.getImageDataMetadata(currentImage);
|
|
175
183
|
|
|
@@ -230,10 +238,17 @@ function _imageChangeEventListener(evt) {
|
|
|
230
238
|
return;
|
|
231
239
|
}
|
|
232
240
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
241
|
+
if (segmentationImageData.setDerivedImage) {
|
|
242
|
+
// Update the derived image data, whether vtk or other as appropriate
|
|
243
|
+
// to the actor(s) displaying the data.
|
|
244
|
+
segmentationImageData.setDerivedImage(derivedImage);
|
|
245
|
+
} else {
|
|
246
|
+
// TODO - use setDerivedImage for this functionality
|
|
247
|
+
utilities.updateVTKImageDataWithCornerstoneImage(
|
|
248
|
+
segmentationImageData,
|
|
249
|
+
derivedImage
|
|
250
|
+
);
|
|
251
|
+
}
|
|
237
252
|
viewport.render();
|
|
238
253
|
|
|
239
254
|
// This is put here to make sure that the segmentation is rendered
|
|
@@ -32,7 +32,6 @@ import { LivewireScissors } from '../../utilities/livewire/LivewireScissors';
|
|
|
32
32
|
import { LivewirePath } from '../../utilities/livewire/LiveWirePath';
|
|
33
33
|
import { getViewportIdsWithToolToRender } from '../../utilities/viewportFilters';
|
|
34
34
|
import ContourSegmentationBaseTool from '../base/ContourSegmentationBaseTool';
|
|
35
|
-
import updateContourPolyline from '../../utilities/contours/updateContourPolyline';
|
|
36
35
|
|
|
37
36
|
const CLICK_CLOSE_CURVE_SQR_DIST = 10 ** 2; // px
|
|
38
37
|
|
|
@@ -108,6 +107,20 @@ class LivewireContourTool extends ContourSegmentationBaseTool {
|
|
|
108
107
|
*/
|
|
109
108
|
showInterpolationPolyline: false,
|
|
110
109
|
},
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* The polyline may get processed in order to reduce the number of points
|
|
113
|
+
* for better performance and storage.
|
|
114
|
+
*/
|
|
115
|
+
decimate: {
|
|
116
|
+
enabled: false,
|
|
117
|
+
/** A maximum given distance 'epsilon' to decide if a point should or
|
|
118
|
+
* shouldn't be added the resulting polyline which will have a lower
|
|
119
|
+
* number of points for higher `epsilon` values.
|
|
120
|
+
*/
|
|
121
|
+
epsilon: 0.1,
|
|
122
|
+
},
|
|
123
|
+
|
|
111
124
|
actions: {
|
|
112
125
|
undo: {
|
|
113
126
|
method: 'undo',
|
|
@@ -922,7 +935,7 @@ class LivewireContourTool extends ContourSegmentationBaseTool {
|
|
|
922
935
|
imagePoints = [...imagePoints, imagePoints[0]];
|
|
923
936
|
}
|
|
924
937
|
|
|
925
|
-
updateContourPolyline(
|
|
938
|
+
this.updateContourPolyline(
|
|
926
939
|
annotation,
|
|
927
940
|
{
|
|
928
941
|
points: imagePoints,
|
|
@@ -231,6 +231,18 @@ class PlanarFreehandROITool extends ContourSegmentationBaseTool {
|
|
|
231
231
|
// interpolation is complete.
|
|
232
232
|
onInterpolationComplete: null,
|
|
233
233
|
},
|
|
234
|
+
/**
|
|
235
|
+
* The polyline may get processed in order to reduce the number of points
|
|
236
|
+
* for better performance and storage.
|
|
237
|
+
*/
|
|
238
|
+
decimate: {
|
|
239
|
+
enabled: false,
|
|
240
|
+
/** A maximum given distance 'epsilon' to decide if a point should or
|
|
241
|
+
* shouldn't be added the resulting polyline which will have a lower
|
|
242
|
+
* number of points for higher `epsilon` values.
|
|
243
|
+
*/
|
|
244
|
+
epsilon: 0.1,
|
|
245
|
+
},
|
|
234
246
|
calculateStats: false,
|
|
235
247
|
getTextLines: defaultGetTextLines,
|
|
236
248
|
statsCalculator: BasicStatsCalculator,
|
|
@@ -56,7 +56,6 @@ import { LinearSpline } from './splines/LinearSpline';
|
|
|
56
56
|
import { CatmullRomSpline } from './splines/CatmullRomSpline';
|
|
57
57
|
import { BSpline } from './splines/BSpline';
|
|
58
58
|
import ContourSegmentationBaseTool from '../base/ContourSegmentationBaseTool';
|
|
59
|
-
import updateContourPolyline from '../../utilities/contours/updateContourPolyline';
|
|
60
59
|
|
|
61
60
|
const SPLINE_MIN_POINTS = 3;
|
|
62
61
|
const SPLINE_CLICK_CLOSE_CURVE_DIST = 10;
|
|
@@ -121,6 +120,18 @@ class SplineROITool extends ContourSegmentationBaseTool {
|
|
|
121
120
|
* modifier must be pressed when the first point of a new contour is added.
|
|
122
121
|
*/
|
|
123
122
|
contourHoleAdditionModifierKey: KeyboardBindings.Shift,
|
|
123
|
+
/**
|
|
124
|
+
* The polyline may get processed in order to reduce the number of points
|
|
125
|
+
* for better performance and storage.
|
|
126
|
+
*/
|
|
127
|
+
decimate: {
|
|
128
|
+
enabled: false,
|
|
129
|
+
/** A maximum given distance 'epsilon' to decide if a point should or
|
|
130
|
+
* shouldn't be added the resulting polyline which will have a lower
|
|
131
|
+
* number of points for higher `epsilon` values.
|
|
132
|
+
*/
|
|
133
|
+
epsilon: 0.1,
|
|
134
|
+
},
|
|
124
135
|
spline: {
|
|
125
136
|
configuration: {
|
|
126
137
|
[SplineTypesEnum.Cardinal]: {
|
|
@@ -693,7 +704,7 @@ class SplineROITool extends ContourSegmentationBaseTool {
|
|
|
693
704
|
const spline = this._updateSplineInstance(element, annotation);
|
|
694
705
|
const splinePolylineCanvas = spline.getPolylinePoints();
|
|
695
706
|
|
|
696
|
-
updateContourPolyline(
|
|
707
|
+
this.updateContourPolyline(
|
|
697
708
|
annotation,
|
|
698
709
|
{
|
|
699
710
|
points: splinePolylineCanvas,
|
|
@@ -18,7 +18,6 @@ import { PlanarFreehandROIAnnotation } from '../../../types/ToolSpecificAnnotati
|
|
|
18
18
|
import findOpenUShapedContourVectorToPeak from './findOpenUShapedContourVectorToPeak';
|
|
19
19
|
import { polyline } from '../../../utilities/math';
|
|
20
20
|
import { removeAnnotation } from '../../../stateManagement/annotation/annotationState';
|
|
21
|
-
import { updateContourPolyline } from '../../../utilities/contours/';
|
|
22
21
|
import reverseIfAntiClockwise from '../../../utilities/contours/reverseIfAntiClockwise';
|
|
23
22
|
|
|
24
23
|
const {
|
|
@@ -238,7 +237,7 @@ function completeDrawClosedContour(
|
|
|
238
237
|
// contours. A future optimization if we use this for segmentation is to re-do
|
|
239
238
|
// this rendering with the GPU rather than SVG.
|
|
240
239
|
|
|
241
|
-
updateContourPolyline(
|
|
240
|
+
this.updateContourPolyline(
|
|
242
241
|
annotation,
|
|
243
242
|
{
|
|
244
243
|
points: updatedPoints,
|
|
@@ -315,7 +314,7 @@ function completeDrawOpenContour(
|
|
|
315
314
|
// contours. A future optimisation if we use this for segmentation is to re-do
|
|
316
315
|
// this rendering with the GPU rather than SVG.
|
|
317
316
|
|
|
318
|
-
updateContourPolyline(
|
|
317
|
+
this.updateContourPolyline(
|
|
319
318
|
annotation,
|
|
320
319
|
{
|
|
321
320
|
points: updatedPoints,
|
|
@@ -17,7 +17,9 @@ import type {
|
|
|
17
17
|
import { drawPath as drawPathSvg } from '../../drawingSvg';
|
|
18
18
|
import { StyleSpecifier } from '../../types/AnnotationStyle';
|
|
19
19
|
import AnnotationTool from './AnnotationTool';
|
|
20
|
+
import { updateContourPolyline } from '../../utilities/contours/';
|
|
20
21
|
import { getContourHolesDataCanvas } from '../../utilities/contours';
|
|
22
|
+
import { ContourWindingDirection } from '../../types/ContourAnnotation';
|
|
21
23
|
|
|
22
24
|
/**
|
|
23
25
|
* A contour base class responsible for rendering contour instances such as
|
|
@@ -210,6 +212,27 @@ abstract class ContourBaseTool extends AnnotationTool {
|
|
|
210
212
|
);
|
|
211
213
|
}
|
|
212
214
|
|
|
215
|
+
protected updateContourPolyline(
|
|
216
|
+
annotation: ContourAnnotation,
|
|
217
|
+
polylineData: {
|
|
218
|
+
points: Types.Point2[];
|
|
219
|
+
closed?: boolean;
|
|
220
|
+
targetWindingDirection?: ContourWindingDirection;
|
|
221
|
+
},
|
|
222
|
+
transforms: {
|
|
223
|
+
canvasToWorld: (point: Types.Point2) => Types.Point3;
|
|
224
|
+
}
|
|
225
|
+
) {
|
|
226
|
+
const decimateConfig = this.configuration?.decimate || {};
|
|
227
|
+
|
|
228
|
+
updateContourPolyline(annotation, polylineData, transforms, {
|
|
229
|
+
decimate: {
|
|
230
|
+
enabled: !!decimateConfig.enabled,
|
|
231
|
+
epsilon: decimateConfig.epsilon,
|
|
232
|
+
},
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
|
|
213
236
|
/**
|
|
214
237
|
* Get polyline points in world space.
|
|
215
238
|
* Just to give a chance for child classes to override it.
|
|
@@ -484,7 +484,7 @@ class BrushTool extends BaseTool {
|
|
|
484
484
|
|
|
485
485
|
this._previewData.preview = this.applyActiveStrategy(
|
|
486
486
|
enabledElement,
|
|
487
|
-
this.getOperationData()
|
|
487
|
+
this.getOperationData(element)
|
|
488
488
|
);
|
|
489
489
|
this._previewData.element = element;
|
|
490
490
|
// Add a bit of time to the timer start so small accidental movements dont
|
|
@@ -15,12 +15,17 @@ import vtkImageData from '@kitware/vtk.js/Common/DataModel/ImageData';
|
|
|
15
15
|
const { VoxelManager } = csUtils;
|
|
16
16
|
|
|
17
17
|
export type InitializedOperationData = LabelmapToolOperationDataAny & {
|
|
18
|
+
// Allow initialization that is operation specific by keying on the name
|
|
19
|
+
operationName?: string;
|
|
20
|
+
|
|
18
21
|
// Additional data for performing the strategy
|
|
19
22
|
enabledElement: Types.IEnabledElement;
|
|
20
23
|
centerIJK?: Types.Point3;
|
|
21
24
|
centerWorld: Types.Point3;
|
|
22
25
|
viewport: Types.IViewport;
|
|
23
|
-
imageVoxelManager:
|
|
26
|
+
imageVoxelManager:
|
|
27
|
+
| csUtils.VoxelManager<number>
|
|
28
|
+
| csUtils.VoxelManager<Types.RGB>;
|
|
24
29
|
segmentationVoxelManager: csUtils.VoxelManager<number>;
|
|
25
30
|
segmentationImageData: vtkImageData;
|
|
26
31
|
previewVoxelManager: csUtils.VoxelManager<number>;
|
|
@@ -152,7 +157,16 @@ export default class BrushStrategy {
|
|
|
152
157
|
enabledElement: Types.IEnabledElement,
|
|
153
158
|
operationData: LabelmapToolOperationDataAny
|
|
154
159
|
) => {
|
|
155
|
-
const initializedData = this.initialize(
|
|
160
|
+
const initializedData = this.initialize(
|
|
161
|
+
enabledElement,
|
|
162
|
+
operationData,
|
|
163
|
+
StrategyCallbacks.Fill
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
if (!initializedData) {
|
|
167
|
+
// Happens when there is no label map
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
156
170
|
|
|
157
171
|
const { strategySpecificConfiguration = {}, centerIJK } = initializedData;
|
|
158
172
|
// Store the center IJK location so that we can skip an immediate same-point update
|
|
@@ -186,7 +200,8 @@ export default class BrushStrategy {
|
|
|
186
200
|
|
|
187
201
|
protected initialize(
|
|
188
202
|
enabledElement: Types.IEnabledElement,
|
|
189
|
-
operationData: LabelmapToolOperationDataAny
|
|
203
|
+
operationData: LabelmapToolOperationDataAny,
|
|
204
|
+
operationName?: string
|
|
190
205
|
): InitializedOperationData {
|
|
191
206
|
const { viewport } = enabledElement;
|
|
192
207
|
const data = getStrategyData({ operationData, viewport });
|
|
@@ -228,6 +243,7 @@ export default class BrushStrategy {
|
|
|
228
243
|
const previewSegmentIndex = previewEnabled ? 255 : undefined;
|
|
229
244
|
|
|
230
245
|
const initializedData: InitializedOperationData = {
|
|
246
|
+
operationName,
|
|
231
247
|
previewSegmentIndex,
|
|
232
248
|
...operationData,
|
|
233
249
|
enabledElement,
|
|
@@ -263,6 +279,10 @@ export default class BrushStrategy {
|
|
|
263
279
|
return;
|
|
264
280
|
}
|
|
265
281
|
const initializedData = this.initialize(enabledElement, operationData);
|
|
282
|
+
if (!initializedData) {
|
|
283
|
+
// Happens if there isn't a labelmap to apply to
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
266
286
|
this._onInteractionStart.forEach((func) =>
|
|
267
287
|
func.call(this, initializedData)
|
|
268
288
|
);
|
|
@@ -334,7 +354,8 @@ function addListMethod(name: string, createInitialized?: string) {
|
|
|
334
354
|
? (enabledElement, operationData) => {
|
|
335
355
|
const initializedData = brushStrategy[createInitialized](
|
|
336
356
|
enabledElement,
|
|
337
|
-
operationData
|
|
357
|
+
operationData,
|
|
358
|
+
name
|
|
338
359
|
);
|
|
339
360
|
brushStrategy[listName].forEach((func) =>
|
|
340
361
|
func.call(brushStrategy, initializedData)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { vec3 } from 'gl-matrix';
|
|
1
2
|
import type { InitializedOperationData } from '../BrushStrategy';
|
|
2
3
|
import type BoundsIJK from '../../../../types/BoundsIJK';
|
|
3
4
|
import StrategyCallbacks from '../../../../enums/StrategyCallbacks';
|
|
@@ -13,6 +14,7 @@ import StrategyCallbacks from '../../../../enums/StrategyCallbacks';
|
|
|
13
14
|
export default {
|
|
14
15
|
[StrategyCallbacks.Initialize]: (operationData: InitializedOperationData) => {
|
|
15
16
|
const {
|
|
17
|
+
operationName,
|
|
16
18
|
centerIJK,
|
|
17
19
|
strategySpecificConfiguration,
|
|
18
20
|
segmentationVoxelManager: segmentationVoxelManager,
|
|
@@ -24,6 +26,12 @@ export default {
|
|
|
24
26
|
if (!THRESHOLD?.isDynamic || !centerIJK || !segmentIndex) {
|
|
25
27
|
return;
|
|
26
28
|
}
|
|
29
|
+
if (
|
|
30
|
+
operationName === StrategyCallbacks.RejectPreview ||
|
|
31
|
+
operationName === StrategyCallbacks.OnInteractionEnd
|
|
32
|
+
) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
27
35
|
|
|
28
36
|
const { boundsIJK } = segmentationVoxelManager;
|
|
29
37
|
const { threshold: oldThreshold, dynamicRadius = 0 } = THRESHOLD;
|
|
@@ -37,9 +45,11 @@ export default {
|
|
|
37
45
|
}) as BoundsIJK;
|
|
38
46
|
|
|
39
47
|
const threshold = oldThreshold || [Infinity, -Infinity];
|
|
48
|
+
// TODO - threshold on all three values separately
|
|
40
49
|
const callback = ({ value }) => {
|
|
41
|
-
|
|
42
|
-
threshold[
|
|
50
|
+
const gray = Array.isArray(value) ? vec3.len(value as any) : value;
|
|
51
|
+
threshold[0] = Math.min(gray, threshold[0]);
|
|
52
|
+
threshold[1] = Math.max(gray, threshold[1]);
|
|
43
53
|
};
|
|
44
54
|
imageVoxelManager.forEach(callback, { boundsIJK: nestedBounds });
|
|
45
55
|
|
|
@@ -89,8 +89,7 @@ export default {
|
|
|
89
89
|
floodedSet.add(index);
|
|
90
90
|
floodedCount++;
|
|
91
91
|
};
|
|
92
|
-
|
|
93
|
-
clickedPoints.forEach((clickedPoint, index) => {
|
|
92
|
+
clickedPoints.forEach((clickedPoint) => {
|
|
94
93
|
// @ts-ignore - need to ignore the spread appication to array params
|
|
95
94
|
if (getter(...clickedPoint) === 1) {
|
|
96
95
|
floodFill(getter, clickedPoint, {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { vec3 } from 'gl-matrix';
|
|
2
|
+
import type { Types } from '@cornerstonejs/core';
|
|
1
3
|
import type { InitializedOperationData } from '../BrushStrategy';
|
|
2
4
|
import StrategyCallbacks from '../../../../enums/StrategyCallbacks';
|
|
3
5
|
|
|
@@ -10,11 +12,8 @@ export default {
|
|
|
10
12
|
[StrategyCallbacks.CreateIsInThreshold]: (
|
|
11
13
|
operationData: InitializedOperationData
|
|
12
14
|
) => {
|
|
13
|
-
const {
|
|
14
|
-
|
|
15
|
-
strategySpecificConfiguration,
|
|
16
|
-
segmentIndex,
|
|
17
|
-
} = operationData;
|
|
15
|
+
const { imageVoxelManager, strategySpecificConfiguration, segmentIndex } =
|
|
16
|
+
operationData;
|
|
18
17
|
if (!strategySpecificConfiguration || !segmentIndex) {
|
|
19
18
|
return;
|
|
20
19
|
}
|
|
@@ -23,13 +22,16 @@ export default {
|
|
|
23
22
|
strategySpecificConfiguration;
|
|
24
23
|
|
|
25
24
|
const voxelValue = imageVoxelManager.getAtIndex(index);
|
|
25
|
+
const gray = Array.isArray(voxelValue)
|
|
26
|
+
? vec3.length(voxelValue as Types.Point3)
|
|
27
|
+
: voxelValue;
|
|
26
28
|
// Prefer the generic version of the THRESHOLD configuration, but fallback
|
|
27
29
|
// to the older THRESHOLD_INSIDE_CIRCLE version.
|
|
28
30
|
const { threshold } = THRESHOLD || THRESHOLD_INSIDE_CIRCLE || {};
|
|
29
31
|
if (!threshold?.length) {
|
|
30
32
|
return true;
|
|
31
33
|
}
|
|
32
|
-
return threshold[0] <=
|
|
34
|
+
return threshold[0] <= gray && gray <= threshold[1];
|
|
33
35
|
};
|
|
34
36
|
},
|
|
35
37
|
};
|
|
@@ -9,6 +9,9 @@ function getStrategyData({ operationData, viewport }) {
|
|
|
9
9
|
let segmentationImageData, segmentationScalarData, imageScalarData;
|
|
10
10
|
let imageDimensions: Types.Point3;
|
|
11
11
|
let segmentationDimensions: Types.Point3;
|
|
12
|
+
let imageVoxelManager;
|
|
13
|
+
let segmentationVoxelManager;
|
|
14
|
+
|
|
12
15
|
if (isVolumeSegmentation(operationData, viewport)) {
|
|
13
16
|
const { volumeId, referencedVolumeId } = operationData;
|
|
14
17
|
|
|
@@ -17,6 +20,7 @@ function getStrategyData({ operationData, viewport }) {
|
|
|
17
20
|
if (!segmentationVolume) {
|
|
18
21
|
return;
|
|
19
22
|
}
|
|
23
|
+
segmentationVoxelManager = segmentationVolume.voxelManager;
|
|
20
24
|
|
|
21
25
|
// we only need the referenceVolumeId if we do thresholding
|
|
22
26
|
// but for other operations we don't need it so make it optional
|
|
@@ -46,32 +50,43 @@ function getStrategyData({ operationData, viewport }) {
|
|
|
46
50
|
// and always circle modifies the current imageId which in fact is the imageData
|
|
47
51
|
// of that actor at that moment so we have the imageData already
|
|
48
52
|
const actor = viewport.getActor(segmentationRepresentationUID);
|
|
53
|
+
if (!actor) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
49
56
|
segmentationImageData = actor.actor.getMapper().getInputData();
|
|
57
|
+
segmentationVoxelManager = segmentationImageData.voxelManager;
|
|
50
58
|
const currentSegmentationImageId = imageIdReferenceMap.get(currentImageId);
|
|
51
59
|
|
|
52
60
|
const segmentationImage = cache.getImage(currentSegmentationImageId);
|
|
53
|
-
|
|
61
|
+
if (!segmentationImage) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
segmentationScalarData = segmentationImage.getPixelData?.();
|
|
54
65
|
|
|
55
66
|
const image = cache.getImage(currentImageId);
|
|
67
|
+
const imageData = image ? null : viewport.getImageData();
|
|
56
68
|
|
|
57
69
|
// VERY IMPORTANT
|
|
58
70
|
// This is the pixel data of the image that is being segmented in the cache
|
|
59
71
|
// and we need to use this to for the modification
|
|
60
|
-
imageScalarData = image
|
|
61
|
-
imageDimensions =
|
|
72
|
+
imageScalarData = image?.getPixelData() || imageData.getScalarData();
|
|
73
|
+
imageDimensions = image
|
|
74
|
+
? [image.columns, image.rows, 1]
|
|
75
|
+
: imageData.dimensions;
|
|
62
76
|
segmentationDimensions = [
|
|
63
77
|
segmentationImage.columns,
|
|
64
78
|
segmentationImage.rows,
|
|
65
79
|
1,
|
|
66
80
|
];
|
|
81
|
+
imageVoxelManager = image?.voxelManager;
|
|
67
82
|
}
|
|
68
83
|
|
|
69
|
-
|
|
84
|
+
segmentationVoxelManager ||= VoxelManager.createVolumeVoxelManager(
|
|
70
85
|
segmentationDimensions,
|
|
71
86
|
segmentationScalarData
|
|
72
87
|
);
|
|
73
88
|
|
|
74
|
-
|
|
89
|
+
imageVoxelManager ||=
|
|
75
90
|
imageDimensions &&
|
|
76
91
|
VoxelManager.createVolumeVoxelManager(imageDimensions, imageScalarData);
|
|
77
92
|
|
|
@@ -14,6 +14,12 @@ import {
|
|
|
14
14
|
* @param viewport - Viewport
|
|
15
15
|
* @param polylineData - Polyline data (points, winding direction and closed)
|
|
16
16
|
* @param transforms - Methods to convert points to/from canvas and world spaces
|
|
17
|
+
* @param options - Options
|
|
18
|
+
* - decimate: allow to set some parameters to decimate the polyline reducing
|
|
19
|
+
* the amount of points stored which also affects how fast it will draw the
|
|
20
|
+
* annotation in a viewport, compute the winding direction, append/remove
|
|
21
|
+
* contours and create holes. A higher `epsilon` value results in a polyline
|
|
22
|
+
* with less points.
|
|
17
23
|
*/
|
|
18
24
|
export default function updateContourPolyline(
|
|
19
25
|
annotation: ContourAnnotation,
|
|
@@ -24,11 +30,27 @@ export default function updateContourPolyline(
|
|
|
24
30
|
},
|
|
25
31
|
transforms: {
|
|
26
32
|
canvasToWorld: (point: Types.Point2) => Types.Point3;
|
|
33
|
+
},
|
|
34
|
+
options?: {
|
|
35
|
+
decimate?: {
|
|
36
|
+
enabled?: boolean;
|
|
37
|
+
epsilon?: number;
|
|
38
|
+
};
|
|
27
39
|
}
|
|
28
40
|
) {
|
|
29
41
|
const { canvasToWorld } = transforms;
|
|
30
42
|
const { data } = annotation;
|
|
31
|
-
const {
|
|
43
|
+
const { targetWindingDirection } = polylineData;
|
|
44
|
+
let { points: polyline } = polylineData;
|
|
45
|
+
|
|
46
|
+
// Decimate the polyline to reduce tha amount of points
|
|
47
|
+
if (options?.decimate?.enabled) {
|
|
48
|
+
polyline = math.polyline.decimate(
|
|
49
|
+
polylineData.points,
|
|
50
|
+
options?.decimate?.epsilon
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
32
54
|
let { closed } = polylineData;
|
|
33
55
|
const numPoints = polyline.length;
|
|
34
56
|
const polylineWorldPoints = new Array(numPoints);
|
|
@@ -24,7 +24,8 @@ export default function distanceToPointSquaredInfo(
|
|
|
24
24
|
let closestPoint: Types.Point2;
|
|
25
25
|
const distanceSquared = math.point.distanceToPointSquared(lineStart, lineEnd);
|
|
26
26
|
|
|
27
|
-
// Check if lineStart
|
|
27
|
+
// Check if lineStart equal to the lineEnd which means the closest point
|
|
28
|
+
// is any of these two points
|
|
28
29
|
if (lineStart[0] === lineEnd[0] && lineStart[1] === lineEnd[1]) {
|
|
29
30
|
closestPoint = lineStart;
|
|
30
31
|
}
|