Skip to content

Commit bfa93c5

Browse files
sedghiwayfarer3130ohif-botdependabot[bot]
authored
feat(segmentation): Simplify preview handling and remove unused code (#1928)
* refactor(segmentation): Simplify preview handling and remove unused code - Removed unnecessary previewVoxelManager references in various files. - Updated createMemo method to eliminate preview parameter. - Cleaned up BrushTool and related strategies to streamline preview logic. - Enhanced code readability by removing commented-out code and redundant checks. * Add some changes * fix undo * works * refactor(segmentation): Improve BrushTool preview handling and memo management - Introduced a memoMap in LabelmapBaseTool to manage multiple memo instances. - Updated createMemo method to handle memo creation and retrieval more efficiently. - Enhanced BrushTool's preview logic by integrating strategy data and memo management. - Removed redundant checks and improved code clarity in preview-related methods. * feat(segmentation): Implement auto-segmentation functionality in ONNXSegmentationController - Added auto-segment mode to ONNXSegmentationController with properties for enabling/disabling and setting the number of random points. - Introduced new methods to handle segmentation logic based on previous images in auto-segment mode. - Created a new example for auto-segmentation in the ai package, integrating UI elements for brush size and toggle functionality. - Enhanced existing viewport classes to support acquisition plane checks. - Updated cache to retrieve images by referenced ImageId. * feat(segmentation): Add undo and redo functionality to labelmap segmentation - Introduced Undo and Redo buttons in the stackLabelmapSegmentation example, utilizing DefaultHistoryMemo for state management. - Enhanced BrushTool to handle labelmap undo events, updating preview data accordingly. - Updated Events enum to include LABELMAP_UNDO for better event handling. - Triggered LABELMAP_UNDO event in createLabelmapMemo to facilitate undo operations. * progress * feat(segmentation): Enhance center segment index management in LabelmapBaseTool - Added centerSegmentIndexInfo to LabelmapBaseTool for improved segment index tracking. - Updated BrushStrategy and related composition strategies to utilize the new centerSegmentIndexInfo structure. - Removed redundant configuration references and streamlined segment index handling in various strategies. - Enhanced preview logic to reset changed indices appropriately. * feat(segmentation): Improve BrushTool preview logic and handling - Enhanced BrushTool's previewCallback to prevent execution during dragging. - Cleared pending preview timers when dragging starts to ensure accurate preview updates. - Updated LabelmapBaseTool to conditionally set previewOnHover based on dragging state. - Modified setValue strategy to prevent previewOnHover from overriding actual segmentation values. * feat(segmentation): Update LabelmapBaseTool to enhance preview logic - Added conditional setting for previewOnHover in LabelmapBaseTool based on dragging state. - Improved user experience by preventing preview during drag operations. * feat(segmentation): Refine setValue strategy for improved preview handling - Added conditional logic to set voxel values based on previewSegmentIndex when centerSegmentIndexInfo is null. - Removed redundant code to streamline the setValue strategy and enhance clarity in preview logic. * feat(segmentation): Add line dash configuration to BrushTool - Introduced conditional lineDash property in BrushTool based on centerSegmentIndexInfo for enhanced visual feedback during segmentation. - Improved user experience by providing a dashed line for the first segment index, aiding in distinguishing between segments. * feat(segmentation): Add DynamicThresholdWithIslandRemoval brush tool - Introduced a new brush instance for DynamicThresholdWithIslandRemoval to enhance segmentation capabilities. - Updated brush strategies and values to include the new tool, improving user options for segmentation. - Modified setupTools function to activate the new brush tool with appropriate configurations. - Ensured that the BrushTool handles operation data correctly to prevent unnecessary execution. * feat(segmentation): Enhance preview functionality in BrushTool and refactor setValue strategy - Enabled the preview feature in the BrushTool configuration for improved user feedback during segmentation. - Refactored the setValue strategy by extracting logic into a new utility function, handleUseSegmentCenterIndex, to streamline the handling of segment indices and improve code clarity. - Removed redundant conditional checks in setValue strategy, enhancing maintainability and readability. Co-authored-by: Bill Wallace <[email protected]> * yarn * chore: try to add depandabot for bun (#1941) * chore: try to add depandabot for bun * try to fix docs * chore(version): version.json [skip ci] * chore(version): Update package versions [skip ci] * chore(deps-dev): bump @babel/runtime from 7.21.5 to 7.26.10 (#1894) Bumps [@babel/runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime) from 7.21.5 to 7.26.10. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.26.10/packages/babel-runtime) --- updated-dependencies: - dependency-name: "@babel/runtime" dependency-type: direct:development ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump @babel/helpers from 7.25.0 to 7.26.10 (#1895) Bumps [@babel/helpers](https://github.com/babel/babel/tree/HEAD/packages/babel-helpers) from 7.25.0 to 7.26.10. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.26.10/packages/babel-helpers) --- updated-dependencies: - dependency-name: "@babel/helpers" dependency-type: indirect ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump @babel/runtime-corejs3 from 7.26.9 to 7.26.10 (#1896) Bumps [@babel/runtime-corejs3](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime-corejs3) from 7.26.9 to 7.26.10. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.26.10/packages/babel-runtime-corejs3) --- updated-dependencies: - dependency-name: "@babel/runtime-corejs3" dependency-type: direct:development ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(version): version.json [skip ci] * chore(version): Update package versions [skip ci] * feat: Enhance labelmap memo functionality and event handling - Added a unique identifier to the Memo type for better tracking. - Introduced LABELMAP_REDO event to handle redo operations for labelmaps. - Updated BrushTool to call the parent handler for accepted memos during undo operations. - Improved memo tracking in LabelmapBaseTool to support auto-accepting previews on redo. - Refactored preview handling in segmentation strategies to utilize the new memo structure. * feat: Refactor event handling for history operations and enhance cache functionality - Introduced a new cache for referenced image IDs to improve image retrieval by referencedImageId. - Updated event handling to replace LABELMAP_UNDO and LABELMAP_REDO with HISTORY_UNDO and HISTORY_REDO for better clarity in history operations. - Enhanced the undoIf method in HistoryMemo to return a boolean indicating if an undo was performed. - Adjusted BrushTool and LabelmapBaseTool to utilize the new history event system. * works fine in the autosegmentai * feat: Enhance cache functionality for referenced image IDs - Added a new cache for referenced image IDs to improve image retrieval by referencedImageId. - Updated methods to manage the addition and removal of referenced image IDs in the cache. - Modified the image loader to support referencedImageId in local image options. * fix: Update default random points and improve random point selection logic in ONNXSegmentationController - Increased the default number of random points from 10 to 25 for better segmentation. - Enhanced the random point selection logic to ensure it does not exceed the available points in pointLists. * feat: Introduce search breadth parameter for improved segmentation point retrieval - Added a new private property `_searchBreadth` to control the search range for neighboring slices. - Updated the logic to check for segmentation points in both previous and next slices based on the specified search breadth, enhancing the accuracy of point selection. * fix * fix build * refactor: Clean up BrushStrategy by removing unused center IJK logic - Removed commented-out code related to center IJK handling to streamline the BrushStrategy class. - Simplified the logic in the brush operation to enhance readability and maintainability. * refactor: Update segmentation identifiers and improve acceptedMemoIds structure - Changed segmentation IDs in stackLabelmapSegmentation example for better clarity. - Refactored acceptedMemoIds from Set to Map in LabelmapBaseTool to store element and segment index. - Updated related logic to utilize the new structure for improved data handling in segmentation operations. * fix * fix build * fix test * Enable center segment index for brush tool for examples * fix the preview undo getting accepted - Removed unused event listener for history redo in LabelmapBaseTool to simplify the code. - Moved the call to doneEditMemo() to ensure it occurs after accepting the preview, improving the accuracy of the timestamp. - Eliminated the clearing of the voxel manager in the preview strategy to enhance performance and maintainability. * fix: Improve preview handling and prevent conflicts with hover - Removed commented-out code related to voxel manager in the preview strategy for clarity. - Added a check to prevent the previewOnHover from overriding the segmentation value, ensuring consistent behavior during interactions. - Included a safeguard to return early if operationData is not provided in the reject preview callback. --------- Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: Bill Wallace <[email protected]> Co-authored-by: ohif-bot <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
1 parent 9a5dc66 commit bfa93c5

File tree

32 files changed

+1251
-361
lines changed

32 files changed

+1251
-361
lines changed

packages/ai/examples/SAMClientSide/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ async function updateViewport() {
253253
};
254254

255255
if (currentViewportType === ViewportType.ORTHOGRAPHIC) {
256-
viewportInput.defaultOptions.orientation = OrientationAxis.SAGITTAL;
256+
viewportInput.defaultOptions.orientation = OrientationAxis.AXIAL;
257257
}
258258

259259
renderingEngine.setViewports([viewportInput]);
Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
import {
2+
Enums,
3+
RenderingEngine,
4+
imageLoader,
5+
setVolumesForViewports,
6+
volumeLoader,
7+
} from '@cornerstonejs/core';
8+
import * as cornerstoneTools from '@cornerstonejs/tools';
9+
import {
10+
createImageIdsAndCacheMetaData,
11+
initDemo,
12+
addToggleButtonToToolbar,
13+
addSliderToToolbar,
14+
addButtonToToolbar,
15+
setTitleAndDescription,
16+
getLocalUrl,
17+
addSegmentIndexDropdown,
18+
} from '../../../../utils/demo/helpers';
19+
import { ONNXSegmentationController } from '@cornerstonejs/ai';
20+
const { MouseBindings, SegmentationRepresentations, Events, KeyboardBindings } =
21+
cornerstoneTools.Enums;
22+
const { ViewportType, OrientationAxis } = Enums;
23+
24+
const { segmentation } = cornerstoneTools;
25+
const { segmentation: segmentationUtils } = cornerstoneTools.utilities;
26+
const currentViewportType = ViewportType.STACK;
27+
28+
setTitleAndDescription(
29+
'Segment Assistant',
30+
'Segment Assistant for Segmentation'
31+
);
32+
33+
// Model configuration for segmentation
34+
const segmentAI = new ONNXSegmentationController({
35+
autoSegmentMode: true,
36+
models: {
37+
sam_b: [
38+
{
39+
name: 'sam-b-encoder',
40+
url: 'https://huggingface.co/schmuell/sam-b-fp16/resolve/main/sam_vit_b_01ec64.encoder-fp16.onnx',
41+
size: 180,
42+
key: 'encoder',
43+
},
44+
{
45+
name: 'sam-b-decoder',
46+
url: 'https://huggingface.co/schmuell/sam-b-fp16/resolve/main/sam_vit_b_01ec64.decoder.onnx',
47+
size: 17,
48+
key: 'decoder',
49+
},
50+
],
51+
},
52+
modelName: 'sam_b',
53+
});
54+
55+
addSliderToToolbar({
56+
title: 'Brush Size',
57+
range: [5, 50],
58+
defaultValue: 25,
59+
onSelectedValueChange: (valueAsStringOrNumber) => {
60+
const value = Number(valueAsStringOrNumber);
61+
segmentationUtils.setBrushSizeForToolGroup(toolGroupId, value);
62+
},
63+
});
64+
65+
addToggleButtonToToolbar({
66+
title: 'Toggle Enable',
67+
onClick: () => {
68+
// Toggle the enable state
69+
segmentAI.enabled = !segmentAI.enabled;
70+
segmentAI.initViewport(viewport);
71+
},
72+
});
73+
74+
const toolGroupId = 'DEFAULT_TOOLGROUP_ID';
75+
const renderingEngineId = 'myRenderingEngine';
76+
const volumeId = 'volumeId';
77+
78+
let renderingEngine;
79+
let viewport;
80+
let activeViewport;
81+
82+
// Add the base tools we need
83+
cornerstoneTools.addTool(cornerstoneTools.PanTool);
84+
cornerstoneTools.addTool(cornerstoneTools.ZoomTool);
85+
cornerstoneTools.addTool(cornerstoneTools.StackScrollTool);
86+
cornerstoneTools.addTool(cornerstoneTools.ProbeTool); // Needed as a base for MarkerInclude/Exclude
87+
cornerstoneTools.addTool(cornerstoneTools.RectangleROITool); // Base for BoxPrompt
88+
cornerstoneTools.addTool(cornerstoneTools.BrushTool); // Base for BoxPrompt
89+
// Create a tool group and add the needed tools
90+
const toolGroup =
91+
cornerstoneTools.ToolGroupManager.createToolGroup(toolGroupId);
92+
93+
toolGroup.addTool(cornerstoneTools.ZoomTool.toolName);
94+
toolGroup.addTool(cornerstoneTools.StackScrollTool.toolName);
95+
toolGroup.addTool(cornerstoneTools.PanTool.toolName);
96+
toolGroup.addTool(cornerstoneTools.ProbeTool.toolName);
97+
toolGroup.addToolInstance(
98+
'CircularBrush',
99+
cornerstoneTools.BrushTool.toolName,
100+
{
101+
activeStrategy: 'FILL_INSIDE_CIRCLE',
102+
preview: {
103+
enabled: true,
104+
},
105+
useCenterSegmentIndex: true,
106+
}
107+
);
108+
109+
// Pan (middle or Ctrl+drag)
110+
toolGroup.setToolActive(cornerstoneTools.PanTool.toolName, {
111+
bindings: [{ mouseButton: MouseBindings.Auxiliary }],
112+
});
113+
toolGroup.setToolPassive(cornerstoneTools.ProbeTool.toolName, {});
114+
115+
// Zoom (right mouse)
116+
toolGroup.setToolActive(cornerstoneTools.ZoomTool.toolName, {
117+
bindings: [
118+
{ mouseButton: MouseBindings.Secondary },
119+
{ mouseButton: MouseBindings.Wheel, modifierKey: KeyboardBindings.Ctrl },
120+
],
121+
});
122+
123+
// Stack Scroll (mouse wheel or Alt+drag)
124+
toolGroup.setToolActive(cornerstoneTools.StackScrollTool.toolName, {
125+
bindings: [{ mouseButton: MouseBindings.Wheel }],
126+
});
127+
toolGroup.setToolActive('CircularBrush', {
128+
bindings: [{ mouseButton: MouseBindings.Primary }],
129+
});
130+
131+
const content = document.getElementById('content');
132+
const viewportContainer = document.createElement('div');
133+
viewportContainer.style.width = '512px';
134+
viewportContainer.style.height = '512px';
135+
viewportContainer.style.position = 'relative';
136+
content.appendChild(viewportContainer);
137+
138+
// Logging elements on the page
139+
const encoderLatency = document.createElement('div');
140+
encoderLatency.id = 'encoder';
141+
content.appendChild(encoderLatency);
142+
143+
const decoderLatency = document.createElement('div');
144+
decoderLatency.id = 'decoder';
145+
content.appendChild(decoderLatency);
146+
147+
const logDiv = document.createElement('div');
148+
logDiv.id = 'status';
149+
content.appendChild(logDiv);
150+
151+
// disable context menu
152+
viewportContainer.oncontextmenu = () => false;
153+
154+
segmentationUtils.setBrushSizeForToolGroup(toolGroupId, 15);
155+
156+
addButtonToToolbar({
157+
title: 'Clear',
158+
onClick: () => {
159+
segmentAI.clear(activeViewport);
160+
viewport.render();
161+
},
162+
});
163+
164+
const viewportId = 'CURRENT_VIEWPORT';
165+
const segmentationId = 'segmentationId';
166+
167+
addSegmentIndexDropdown(segmentationId);
168+
169+
async function updateViewport() {
170+
await initDemo();
171+
172+
if (renderingEngine) {
173+
// renderingEngine.destroy();
174+
segmentation.removeAllSegmentationRepresentations();
175+
segmentation.removeAllSegmentations();
176+
}
177+
178+
renderingEngine = new RenderingEngine(renderingEngineId);
179+
180+
const viewportInput = {
181+
viewportId,
182+
element: viewportContainer,
183+
type: currentViewportType,
184+
defaultOptions: {},
185+
};
186+
187+
if (currentViewportType === ViewportType.ORTHOGRAPHIC) {
188+
viewportInput.defaultOptions.orientation = OrientationAxis.SAGITTAL;
189+
}
190+
191+
renderingEngine.setViewports([viewportInput]);
192+
toolGroup.addViewport(viewportId, renderingEngineId);
193+
194+
const imageIds = await createAndLoadData();
195+
196+
if (currentViewportType === ViewportType.STACK) {
197+
viewport = renderingEngine.getViewport(viewportId);
198+
await viewport.setStack(imageIds.reverse().slice(50, 190));
199+
200+
cornerstoneTools.utilities.stackContextPrefetch.enable(viewportContainer);
201+
viewport.render();
202+
} else {
203+
// For sagittal, create volume and set it
204+
const volume = await volumeLoader.createAndCacheVolume(volumeId, {
205+
imageIds,
206+
});
207+
volume.load();
208+
await setVolumesForViewports(renderingEngine, [{ volumeId }], [viewportId]);
209+
viewport = renderingEngine.getViewport(viewportId);
210+
viewport.render();
211+
}
212+
213+
// Add a segmentation that will contains the contour annotations
214+
const segmentationImages =
215+
await imageLoader.createAndCacheDerivedLabelmapImages(imageIds);
216+
217+
const segmentationImageIds = segmentationImages.map((image) => image.imageId);
218+
219+
segmentation.addSegmentations([
220+
{
221+
segmentationId,
222+
representation: {
223+
type: SegmentationRepresentations.Labelmap,
224+
data: {
225+
imageIds: segmentationImageIds,
226+
},
227+
},
228+
},
229+
]);
230+
231+
const segMap = {
232+
[viewport.id]: [{ segmentationId }],
233+
};
234+
235+
// Create a segmentation representation associated to the toolGroupId
236+
await segmentation.addLabelmapRepresentationToViewportMap(segMap);
237+
238+
activeViewport = viewport;
239+
await segmentAI.initModel();
240+
241+
viewport.element.addEventListener(Events.KEY_DOWN, (evt) => {
242+
const { key } = evt.detail;
243+
const { element } = activeViewport;
244+
if (key === 'Escape') {
245+
cornerstoneTools.cancelActiveManipulations(element);
246+
segmentAI.rejectPreview(element);
247+
} else if (key === 'Enter') {
248+
segmentAI.acceptPreview(element);
249+
}
250+
});
251+
}
252+
253+
async function createAndLoadData() {
254+
const imageIdsFull = await createImageIdsAndCacheMetaData({
255+
StudyInstanceUID:
256+
'1.3.6.1.4.1.14519.5.2.1.7009.2403.334240657131972136850343327463',
257+
SeriesInstanceUID:
258+
'1.3.6.1.4.1.14519.5.2.1.7009.2403.226151125820845824875394858561',
259+
wadoRsRoot:
260+
getLocalUrl() || 'https://d14fa38qiwhyfd.cloudfront.net/dicomweb',
261+
});
262+
return imageIdsFull.reverse();
263+
}
264+
265+
updateViewport();

0 commit comments

Comments
 (0)