@cornerstonejs/ai 3.8.1 → 3.8.2

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/README.md CHANGED
@@ -9,6 +9,25 @@ This package provides AI interfaces for use with Cornerstone in client-side appl
9
9
 
10
10
  ## Getting Started
11
11
 
12
+ ### WASM Files
13
+
14
+ The ONNX Runtime Web requires WASM files to run in the browser. These files need to be copied to your application's public directory. The files should be placed in an `/ort/` directory in your public folder.
15
+
16
+ In Webpack you can add the WASM files to the public folder like this:
17
+
18
+ ```js
19
+ new CopyPlugin({
20
+ patterns: [
21
+ {
22
+ from: '../../../node_modules/onnxruntime-web/dist',
23
+ to: '${destPath.replace(/\\/g, '/')}/ort',
24
+ },
25
+ ],
26
+ }),
27
+ ```
28
+
29
+ This will copy all the necessary WASM files from the ONNX Runtime Web package to your application's public directory. Make sure your build system is configured to handle WASM files and that the `asyncWebAssembly` experiment is enabled in your build configuration.
30
+
12
31
  ### Running the Example
13
32
 
14
33
  To see the package in action with the Segment Anything Model, use the following command:
@@ -37,7 +56,6 @@ Huge model (vit_h) - 2.38 GB compressed
37
56
 
38
57
  For the examples we are using the model url and fetch it from the web. If you see in example code we have:
39
58
 
40
-
41
59
  #### URL to the model files
42
60
 
43
61
  ```js
@@ -0,0 +1,34 @@
1
+ import { LabelmapBaseTool } from '@cornerstonejs/tools';
2
+ declare class LabelmapSlicePropagationTool extends LabelmapBaseTool {
3
+ static toolName: string;
4
+ private segmentAI;
5
+ private _initialized;
6
+ private _modelInitialized;
7
+ constructor(toolProps?: {}, defaultToolProps?: {
8
+ supportedInteractionTypes: string[];
9
+ configuration: {
10
+ sourceViewportId: string;
11
+ autoSegmentMode: boolean;
12
+ modelName: string;
13
+ enabled: boolean;
14
+ models: {
15
+ sam_b: {
16
+ name: string;
17
+ url: string;
18
+ size: number;
19
+ key: string;
20
+ }[];
21
+ };
22
+ numRandomPoints: number;
23
+ searchBreadth: number;
24
+ };
25
+ });
26
+ _init: () => Promise<void>;
27
+ onSetToolConfiguration: () => void;
28
+ onSetToolEnabled: () => Promise<void>;
29
+ onSetToolDisabled: () => void;
30
+ onSetToolPassive: () => void;
31
+ acceptPreview: () => void;
32
+ rejectPreview: () => void;
33
+ }
34
+ export default LabelmapSlicePropagationTool;
@@ -0,0 +1,106 @@
1
+ import { getEnabledElementByViewportId } from '@cornerstonejs/core';
2
+ import { LabelmapBaseTool } from '@cornerstonejs/tools';
3
+ import ONNXSegmentationController from './ONNXSegmentationController';
4
+ class LabelmapSlicePropagationTool extends LabelmapBaseTool {
5
+ static { this.toolName = 'LabelmapSlicePropagation'; }
6
+ constructor(toolProps = {}, defaultToolProps = {
7
+ supportedInteractionTypes: ['Mouse', 'Touch'],
8
+ configuration: {
9
+ sourceViewportId: '',
10
+ autoSegmentMode: true,
11
+ modelName: 'sam_b',
12
+ enabled: false,
13
+ models: {
14
+ sam_b: [
15
+ {
16
+ name: 'sam-b-encoder',
17
+ url: 'https://huggingface.co/schmuell/sam-b-fp16/resolve/main/sam_vit_b_01ec64.encoder-fp16.onnx',
18
+ size: 180,
19
+ key: 'encoder',
20
+ },
21
+ {
22
+ name: 'sam-b-decoder',
23
+ url: 'https://huggingface.co/schmuell/sam-b-fp16/resolve/main/sam_vit_b_01ec64.decoder.onnx',
24
+ size: 17,
25
+ key: 'decoder',
26
+ },
27
+ ],
28
+ },
29
+ numRandomPoints: 5,
30
+ searchBreadth: 10,
31
+ },
32
+ }) {
33
+ super(toolProps, defaultToolProps);
34
+ this._initialized = false;
35
+ this._modelInitialized = false;
36
+ this._init = async () => {
37
+ const { configuration } = this;
38
+ if (!configuration.enabled || !configuration.sourceViewportId) {
39
+ return;
40
+ }
41
+ if (!this.segmentAI) {
42
+ this.segmentAI = new ONNXSegmentationController({
43
+ autoSegmentMode: configuration.autoSegmentMode,
44
+ models: configuration.models,
45
+ modelName: configuration.modelName,
46
+ numRandomPoints: configuration.numRandomPoints,
47
+ searchBreadth: configuration.searchBreadth,
48
+ });
49
+ }
50
+ this.segmentAI.enabled = true;
51
+ if (!this._modelInitialized) {
52
+ await this.segmentAI.initModel();
53
+ this._modelInitialized = true;
54
+ }
55
+ const { sourceViewportId } = this.configuration;
56
+ const enabledElement = getEnabledElementByViewportId(sourceViewportId);
57
+ if (!enabledElement) {
58
+ console.debug('No enabled element found for viewportId:', sourceViewportId);
59
+ return;
60
+ }
61
+ const { viewport } = enabledElement;
62
+ this.segmentAI.initViewport(viewport);
63
+ this._initialized = true;
64
+ };
65
+ this.onSetToolConfiguration = () => {
66
+ this._init();
67
+ };
68
+ this.onSetToolEnabled = async () => {
69
+ this.configuration.enabled = true;
70
+ if (this.segmentAI) {
71
+ this.segmentAI.enabled = true;
72
+ }
73
+ this._init();
74
+ };
75
+ this.onSetToolDisabled = () => {
76
+ this.configuration.enabled = false;
77
+ if (this.segmentAI) {
78
+ this.segmentAI.enabled = false;
79
+ }
80
+ };
81
+ this.onSetToolPassive = () => {
82
+ this.configuration.enabled = false;
83
+ if (this.segmentAI) {
84
+ this.segmentAI.enabled = false;
85
+ }
86
+ };
87
+ this.acceptPreview = () => {
88
+ const { sourceViewportId } = this.configuration;
89
+ const enabledElement = getEnabledElementByViewportId(sourceViewportId);
90
+ if (!enabledElement) {
91
+ return;
92
+ }
93
+ const { viewport } = enabledElement;
94
+ this.segmentAI.tool.acceptPreview(viewport.element);
95
+ };
96
+ this.rejectPreview = () => {
97
+ const { sourceViewportId } = this.configuration;
98
+ const enabledElement = getEnabledElementByViewportId(sourceViewportId);
99
+ if (!enabledElement) {
100
+ return;
101
+ }
102
+ this.segmentAI.rejectPreview(enabledElement.viewport.element);
103
+ };
104
+ }
105
+ }
106
+ export default LabelmapSlicePropagationTool;
@@ -0,0 +1,39 @@
1
+ import { LabelmapBaseTool } from '@cornerstonejs/tools';
2
+ declare class MarkerLabelmapTool extends LabelmapBaseTool {
3
+ static toolName: string;
4
+ private segmentAI;
5
+ private _initialized;
6
+ private _modelInitialized;
7
+ private _toolsAdded;
8
+ constructor(toolProps?: {}, defaultToolProps?: {
9
+ supportedInteractionTypes: string[];
10
+ configuration: {
11
+ sourceViewportId: string;
12
+ modelName: string;
13
+ enabled: boolean;
14
+ models: {
15
+ sam_b: {
16
+ name: string;
17
+ url: string;
18
+ size: number;
19
+ key: string;
20
+ }[];
21
+ };
22
+ numRandomPoints: number;
23
+ searchBreadth: number;
24
+ };
25
+ });
26
+ _init: () => Promise<void>;
27
+ _getToolGroupId: () => import("packages/tools/dist/esm/types").IToolGroup;
28
+ _addToolInstances: () => void;
29
+ onSetToolConfiguration: () => void;
30
+ onSetToolEnabled: () => Promise<void>;
31
+ onSetToolActive: () => void;
32
+ interpolateScroll: () => void;
33
+ onSetToolDisabled: () => void;
34
+ clearMarkers: () => void;
35
+ removePromptAnnotations: () => void;
36
+ acceptPreview: () => void;
37
+ rejectPreview: () => void;
38
+ }
39
+ export default MarkerLabelmapTool;
@@ -0,0 +1,176 @@
1
+ import { getEnabledElementByViewportId } from '@cornerstonejs/core';
2
+ import { LabelmapBaseTool, ToolGroupManager, Enums, annotation, ProbeTool, RectangleROITool, addTool, } from '@cornerstonejs/tools';
3
+ import ONNXSegmentationController from './ONNXSegmentationController';
4
+ class MarkerLabelmapTool extends LabelmapBaseTool {
5
+ static { this.toolName = 'MarkerLabelmap'; }
6
+ constructor(toolProps = {}, defaultToolProps = {
7
+ supportedInteractionTypes: ['Mouse', 'Touch'],
8
+ configuration: {
9
+ sourceViewportId: '',
10
+ modelName: 'sam_b',
11
+ enabled: false,
12
+ models: {
13
+ sam_b: [
14
+ {
15
+ name: 'sam-b-encoder',
16
+ url: 'https://huggingface.co/schmuell/sam-b-fp16/resolve/main/sam_vit_b_01ec64.encoder-fp16.onnx',
17
+ size: 180,
18
+ key: 'encoder',
19
+ },
20
+ {
21
+ name: 'sam-b-decoder',
22
+ url: 'https://huggingface.co/schmuell/sam-b-fp16/resolve/main/sam_vit_b_01ec64.decoder.onnx',
23
+ size: 17,
24
+ key: 'decoder',
25
+ },
26
+ ],
27
+ },
28
+ numRandomPoints: 5,
29
+ searchBreadth: 10,
30
+ },
31
+ }) {
32
+ super(toolProps, defaultToolProps);
33
+ this._initialized = false;
34
+ this._modelInitialized = false;
35
+ this._toolsAdded = false;
36
+ this._init = async () => {
37
+ const { configuration } = this;
38
+ if (!configuration.enabled || !configuration.sourceViewportId) {
39
+ return;
40
+ }
41
+ if (!this.segmentAI) {
42
+ this.segmentAI = new ONNXSegmentationController({
43
+ models: configuration.models,
44
+ modelName: configuration.modelName,
45
+ });
46
+ }
47
+ if (!this._toolsAdded) {
48
+ this._addToolInstances();
49
+ }
50
+ this.segmentAI.enabled = true;
51
+ if (!this._modelInitialized) {
52
+ await this.segmentAI.initModel();
53
+ this._modelInitialized = true;
54
+ }
55
+ const { sourceViewportId } = this.configuration;
56
+ const enabledElement = getEnabledElementByViewportId(sourceViewportId);
57
+ if (!enabledElement) {
58
+ console.debug('No enabled element found for viewportId:', sourceViewportId);
59
+ return;
60
+ }
61
+ const { viewport } = enabledElement;
62
+ this.segmentAI.initViewport(viewport);
63
+ this._initialized = true;
64
+ };
65
+ this._getToolGroupId = () => {
66
+ return ToolGroupManager.getToolGroupForViewport(this.configuration.sourceViewportId);
67
+ };
68
+ this._addToolInstances = () => {
69
+ const toolGroup = this._getToolGroupId();
70
+ if (!toolGroup) {
71
+ console.debug(`Tool group not found`);
72
+ return;
73
+ }
74
+ addTool(ProbeTool);
75
+ const MarkerIncludeToolName = ONNXSegmentationController.MarkerInclude;
76
+ const MarkerExcludeToolName = ONNXSegmentationController.MarkerExclude;
77
+ const BoxPromptToolName = ONNXSegmentationController.BoxPrompt;
78
+ toolGroup.addToolInstance(MarkerIncludeToolName, ProbeTool.toolName, {
79
+ getTextLines: () => null,
80
+ });
81
+ toolGroup.addToolInstance(MarkerExcludeToolName, ProbeTool.toolName, {
82
+ getTextLines: () => null,
83
+ });
84
+ annotation.config.style.setToolGroupToolStyles(toolGroup.id, {
85
+ [MarkerIncludeToolName]: {
86
+ color: 'rgb(0, 255, 0)',
87
+ colorHighlighted: 'rgb(0, 255, 0)',
88
+ colorSelected: 'rgb(0, 255, 0)',
89
+ },
90
+ [MarkerExcludeToolName]: {
91
+ color: 'rgb(255, 0, 0)',
92
+ colorHighlighted: 'rgb(255, 0, 0)',
93
+ colorSelected: 'rgb(255, 0, 0)',
94
+ },
95
+ });
96
+ this._toolsAdded = true;
97
+ };
98
+ this.onSetToolConfiguration = () => {
99
+ this._init();
100
+ };
101
+ this.onSetToolEnabled = async () => {
102
+ this.configuration.enabled = true;
103
+ if (this.segmentAI) {
104
+ this.segmentAI.enabled = true;
105
+ }
106
+ if (!this._initialized) {
107
+ await this._init();
108
+ }
109
+ };
110
+ this.onSetToolActive = () => {
111
+ this.configuration.enabled = true;
112
+ if (this.segmentAI) {
113
+ this.segmentAI.enabled = true;
114
+ }
115
+ if (!this._initialized) {
116
+ this._init();
117
+ }
118
+ };
119
+ this.interpolateScroll = () => {
120
+ this.segmentAI.interpolateScroll();
121
+ };
122
+ this.onSetToolDisabled = () => {
123
+ this.configuration.enabled = false;
124
+ if (this.segmentAI) {
125
+ this.segmentAI.enabled = false;
126
+ }
127
+ };
128
+ this.clearMarkers = () => {
129
+ if (!this.segmentAI) {
130
+ return;
131
+ }
132
+ const { sourceViewportId } = this.configuration;
133
+ const enabledElement = getEnabledElementByViewportId(sourceViewportId);
134
+ if (!enabledElement) {
135
+ return;
136
+ }
137
+ const { viewport } = enabledElement;
138
+ this.segmentAI.clear(viewport);
139
+ viewport.render();
140
+ };
141
+ this.removePromptAnnotations = () => {
142
+ if (!this.segmentAI) {
143
+ return;
144
+ }
145
+ const { viewportId } = this.configuration;
146
+ const enabledElement = getEnabledElementByViewportId(viewportId);
147
+ if (!enabledElement) {
148
+ return;
149
+ }
150
+ this.segmentAI.removePromptAnnotationsWithCache(enabledElement.viewport);
151
+ };
152
+ this.acceptPreview = () => {
153
+ if (!this.segmentAI) {
154
+ return;
155
+ }
156
+ const { sourceViewportId } = this.configuration;
157
+ const enabledElement = getEnabledElementByViewportId(sourceViewportId);
158
+ if (!enabledElement) {
159
+ return;
160
+ }
161
+ this.segmentAI.acceptPreview(enabledElement.viewport.element);
162
+ };
163
+ this.rejectPreview = () => {
164
+ if (!this.segmentAI) {
165
+ return;
166
+ }
167
+ const { sourceViewportId } = this.configuration;
168
+ const enabledElement = getEnabledElementByViewportId(sourceViewportId);
169
+ if (!enabledElement) {
170
+ return;
171
+ }
172
+ this.segmentAI.rejectPreview(enabledElement.viewport.element);
173
+ };
174
+ }
175
+ }
176
+ export default MarkerLabelmapTool;
@@ -93,15 +93,18 @@ export default class ONNXSegmentationController {
93
93
  };
94
94
  protected pCutoff: number;
95
95
  constructor(options?: {
96
- listeners: any;
97
- getPromptAnnotations: any;
98
- promptAnnotationTypes: any;
99
- models: any;
100
- modelName: any;
101
- islandFillOptions: any;
102
- autoSegmentMode: boolean;
103
- numRandomPoints: number;
104
- searchBreadth: number;
96
+ listeners?: Array<(message: string) => void>;
97
+ getPromptAnnotations?: (viewport?: Types.IViewport) => cornerstoneTools.Types.Annotation[];
98
+ promptAnnotationTypes?: string[];
99
+ models?: Record<string, ModelType[]>;
100
+ modelName?: string;
101
+ islandFillOptions?: {
102
+ maxInternalRemove?: number;
103
+ fillInternalEdge?: boolean;
104
+ };
105
+ autoSegmentMode?: boolean;
106
+ numRandomPoints?: number;
107
+ searchBreadth?: number;
105
108
  });
106
109
  set enabled(enabled: boolean);
107
110
  get enabled(): boolean;
@@ -115,7 +115,10 @@ export default class ONNXSegmentationController {
115
115
  promptAnnotationTypes: null,
116
116
  models: null,
117
117
  modelName: null,
118
- islandFillOptions: undefined,
118
+ islandFillOptions: {
119
+ maxInternalRemove: 16,
120
+ fillInternalEdge: true,
121
+ },
119
122
  autoSegmentMode: false,
120
123
  numRandomPoints: 2,
121
124
  searchBreadth: 3,
@@ -276,8 +279,14 @@ export default class ONNXSegmentationController {
276
279
  Object.assign(ONNXSegmentationController.MODELS, options.models);
277
280
  }
278
281
  this.config = this.getConfig(options.modelName);
279
- this.islandFillOptions =
280
- options.islandFillOptions ?? this.islandFillOptions;
282
+ if (options.islandFillOptions) {
283
+ this.islandFillOptions = {
284
+ maxInternalRemove: options.islandFillOptions.maxInternalRemove ??
285
+ this.islandFillOptions.maxInternalRemove,
286
+ fillInternalEdge: options.islandFillOptions.fillInternalEdge ??
287
+ this.islandFillOptions.fillInternalEdge,
288
+ };
289
+ }
281
290
  this._autoSegmentMode = options.autoSegmentMode || false;
282
291
  this.numRandomPoints = options.numRandomPoints || this.numRandomPoints;
283
292
  this._searchBreadth = options.searchBreadth || this._searchBreadth;
@@ -470,7 +479,9 @@ export default class ONNXSegmentationController {
470
479
  this.points = [];
471
480
  this.labels = [];
472
481
  this.getPromptAnnotations(viewport).forEach((annotation) => annotationState.removeAnnotation(annotation.annotationUID));
473
- this.tool.rejectPreview(this.viewport.element);
482
+ if (this.tool) {
483
+ this.tool.rejectPreview(this.viewport.element);
484
+ }
474
485
  }
475
486
  async cacheImageEncodings(current = this.viewport.getCurrentImageIdIndex(), offset = 0, length = 1000_000) {
476
487
  const { viewport, imageEncodings } = this;
@@ -504,7 +515,7 @@ export default class ONNXSegmentationController {
504
515
  });
505
516
  }
506
517
  async handleImage({ imageId, sampleImageId }, imageSession) {
507
- if (imageId === imageSession.imageId || this.isGpuInUse) {
518
+ if (imageId === imageSession.imageId || this.isGpuInUse || !this.enabled) {
508
519
  return;
509
520
  }
510
521
  const { viewport, desiredImage } = this;
@@ -613,7 +624,7 @@ export default class ONNXSegmentationController {
613
624
  this.currentImage = null;
614
625
  }
615
626
  const [session] = this.sessions;
616
- if (session.imageId === desiredImage.imageId) {
627
+ if (session?.imageId === desiredImage.imageId) {
617
628
  if (this.currentImage !== session) {
618
629
  this.currentImage = session;
619
630
  }
@@ -761,7 +772,7 @@ export default class ONNXSegmentationController {
761
772
  const maskIndex = 4 * (i + j * this.maxWidth);
762
773
  const v = data[maskIndex];
763
774
  const segmentValue = segmentationVoxelManager.getAtIJKPoint(ijkPoint);
764
- if (segmentValue !== 0) {
775
+ if (segmentValue !== 0 && segmentValue !== 255) {
765
776
  continue;
766
777
  }
767
778
  if (v > this.pCutoff) {
@@ -772,7 +783,9 @@ export default class ONNXSegmentationController {
772
783
  }
773
784
  }
774
785
  }
775
- this.tool.doneEditMemo();
786
+ if (this._autoSegmentMode) {
787
+ this.tool.doneEditMemo();
788
+ }
776
789
  this.tool._previewData.isDrag = true;
777
790
  const voxelManager = previewVoxelManager.sourceVoxelManager || previewVoxelManager;
778
791
  if (this.islandFillOptions) {
@@ -995,7 +1008,7 @@ export default class ONNXSegmentationController {
995
1008
  }
996
1009
  config.threads = parseInt(String(config.threads));
997
1010
  config.local = parseInt(config.local);
998
- ort.env.wasm.wasmPaths = 'dist/';
1011
+ ort.env.wasm.wasmPaths = 'ort/';
999
1012
  ort.env.wasm.numThreads = config.threads;
1000
1013
  ort.env.wasm.proxy = config.provider == 'wasm';
1001
1014
  this.config = config;
@@ -1,2 +1,4 @@
1
1
  import ONNXSegmentationController from './ONNXSegmentationController';
2
- export { ONNXSegmentationController };
2
+ import LabelmapSlicePropagationTool from './LabelmapSlicePropagationTool';
3
+ import MarkerLabelmapTool from './MarkerLabelmapTool';
4
+ export { ONNXSegmentationController, LabelmapSlicePropagationTool, MarkerLabelmapTool, };
package/dist/esm/index.js CHANGED
@@ -1,2 +1,4 @@
1
1
  import ONNXSegmentationController from './ONNXSegmentationController';
2
- export { ONNXSegmentationController };
2
+ import LabelmapSlicePropagationTool from './LabelmapSlicePropagationTool';
3
+ import MarkerLabelmapTool from './MarkerLabelmapTool';
4
+ export { ONNXSegmentationController, LabelmapSlicePropagationTool, MarkerLabelmapTool, };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cornerstonejs/ai",
3
- "version": "3.8.1",
3
+ "version": "3.8.2",
4
4
  "description": "AI and ML Interfaces for Cornerstone3D",
5
5
  "files": [
6
6
  "dist"
@@ -56,8 +56,8 @@
56
56
  "onnxruntime-web": "1.17.1"
57
57
  },
58
58
  "peerDependencies": {
59
- "@cornerstonejs/core": "^3.8.1",
60
- "@cornerstonejs/tools": "^3.8.1"
59
+ "@cornerstonejs/core": "^3.8.2",
60
+ "@cornerstonejs/tools": "^3.8.2"
61
61
  },
62
- "gitHead": "1f45d352ecb6e239cb418f085cdabeca2a4520a9"
62
+ "gitHead": "d14852bdc9402b62ca685c559663438c19079e07"
63
63
  }