diff --git a/packages/adapters/examples/segmentationStack/index.ts b/packages/adapters/examples/segmentationStack/index.ts index 0c7f83999..1c7b11c09 100644 --- a/packages/adapters/examples/segmentationStack/index.ts +++ b/packages/adapters/examples/segmentationStack/index.ts @@ -2,13 +2,11 @@ import { api } from "dicomweb-client"; import * as cornerstone from "@cornerstonejs/core"; import * as cornerstoneTools from "@cornerstonejs/tools"; -import * as cornerstoneAdapters from "@cornerstonejs/adapters"; import { dicomMap } from "./demo"; import { addButtonToToolbar, - addDropdownToToolbar, addManipulationBindings, addToggleButtonToToolbar, addUploadToToolbar, @@ -26,7 +24,7 @@ console.warn( ); const { Enums: csEnums, RenderingEngine, utilities: csUtilities } = cornerstone; -const { ViewportType } = csEnums; +const { segmentation: csToolsSegmentation } = cornerstoneTools; import { readDicom, loadDicom, @@ -36,7 +34,8 @@ import { restart, getSegmentationIds, handleFileSelect, - handleDragOver + handleDragOver, + createSegmentation } from "../segmentationVolume/utils"; const referenceImageIds: string[] = []; @@ -135,6 +134,13 @@ function loadDicom() { renderingEngine.render(); } +function createSegmentationRepresentation() { + csToolsSegmentation.addLabelmapRepresentationToViewport( + state.viewportIds[0], + [{ segmentationId: state.segmentationId }] + ); +} + // ============================= // addButtonToToolbar({ id: "LOAD_DICOM", @@ -169,6 +175,7 @@ addButtonToToolbar({ }); await loadSegmentation(arrayBuffer, state); + createSegmentationRepresentation(); }, container: group1 }); @@ -176,9 +183,19 @@ addButtonToToolbar({ addUploadToToolbar({ id: "IMPORT_DICOM", title: "Import DICOM", - onChange: (files: FileList) => { - readDicom(files, state); - loadDicom(); + onChange: async (files: FileList) => { + await readDicom(files, state); + await loadDicom(); + }, + container: group2 +}); + +addButtonToToolbar({ + id: "CREATE_SEGMENTATION", + title: "Create Empty SEG", + onClick: async () => { + await createSegmentation(state); + createSegmentationRepresentation(); }, container: group2 }); @@ -190,6 +207,8 @@ addUploadToToolbar({ for (const file of files) { await readSegmentation(file, state); } + + createSegmentationRepresentation(); }, container: group2 }); diff --git a/packages/adapters/examples/segmentationVolume/index.ts b/packages/adapters/examples/segmentationVolume/index.ts index 873452c7c..61bc2b3ea 100644 --- a/packages/adapters/examples/segmentationVolume/index.ts +++ b/packages/adapters/examples/segmentationVolume/index.ts @@ -24,6 +24,7 @@ console.warn( ); const { utilities: csUtilities } = cornerstone; +const { segmentation: csToolsSegmentation } = cornerstoneTools; import { readDicom, readSegmentation, @@ -31,7 +32,8 @@ import { exportSegmentation, handleFileSelect, handleDragOver, - restart + restart, + createSegmentation } from "../segmentationVolume/utils"; setTitleAndDescription( @@ -158,6 +160,15 @@ async function loadDicom() { renderingEngine.render(); } +function createSegmentationRepresentation() { + const segMap = { + [state.viewportIds[0]]: [{ segmentationId: state.segmentationId }], + [state.viewportIds[1]]: [{ segmentationId: state.segmentationId }], + [state.viewportIds[2]]: [{ segmentationId: state.segmentationId }] + }; + + csToolsSegmentation.addLabelmapRepresentationToViewportMap(segMap); +} // ============================= // addButtonToToolbar({ id: "LOAD_DICOM", @@ -191,6 +202,7 @@ addButtonToToolbar({ }); await loadSegmentation(arrayBuffer, state); + createSegmentationRepresentation(); }, container: group1 }); @@ -198,7 +210,20 @@ addButtonToToolbar({ addUploadToToolbar({ id: "IMPORT_DICOM", title: "Import DICOM", - onChange: (files: FileList) => readDicom(files, state), + onChange: async (files: FileList) => { + await readDicom(files, state); + await loadDicom(); + }, + container: group2 +}); + +addButtonToToolbar({ + id: "CREATE_SEGMENTATION", + title: "Create Empty SEG", + onClick: async () => { + await createSegmentation(state); + createSegmentationRepresentation(); + }, container: group2 }); @@ -213,6 +238,8 @@ addUploadToToolbar({ for (const file of files) { await readSegmentation(file, state); } + + createSegmentationRepresentation(); }, container: group2 }); diff --git a/packages/adapters/examples/segmentationVolume/utils.ts b/packages/adapters/examples/segmentationVolume/utils.ts index bb6f5902c..8baed9164 100644 --- a/packages/adapters/examples/segmentationVolume/utils.ts +++ b/packages/adapters/examples/segmentationVolume/utils.ts @@ -4,26 +4,13 @@ import * as cornerstoneDicomImageLoader from "@cornerstonejs/dicom-image-loader" import * as cornerstoneAdapters from "@cornerstonejs/adapters"; import dcmjs from "dcmjs"; -const { - cache, - imageLoader, - metaData, - utilities: csUtilities, - volumeLoader -} = cornerstone; +const { cache, imageLoader, metaData } = cornerstone; const { segmentation: csToolsSegmentation } = cornerstoneTools; const { wadouri } = cornerstoneDicomImageLoader; const { downloadDICOMData } = cornerstoneAdapters.helpers; const { Cornerstone3D } = cornerstoneAdapters.adaptersSEG; export async function readDicom(files: FileList, state) { - if (files.length <= 1) { - console.error( - "Viewport volume does not support just one image, it must be two or more images" - ); - return; - } - for (const file of files) { const imageId = wadouri.fileManager.add(file); await imageLoader.loadAndCacheImage(imageId); @@ -31,6 +18,32 @@ export async function readDicom(files: FileList, state) { } } +export async function createSegmentation(state) { + const { referenceImageIds, segmentationId } = state; + + const derivedSegmentationImages = + await imageLoader.createAndCacheDerivedLabelmapImages( + referenceImageIds + ); + + const derivedSegmentationImageIds = derivedSegmentationImages.map( + image => image.imageId + ); + + csToolsSegmentation.addSegmentations([ + { + segmentationId, + representation: { + type: cornerstoneTools.Enums.SegmentationRepresentations + .Labelmap, + data: { + imageIds: derivedSegmentationImageIds + } + } + } + ]); +} + export async function readSegmentation(file: File, state) { const imageId = wadouri.fileManager.add(file); const image = await imageLoader.loadAndCacheImage(imageId); @@ -52,8 +65,7 @@ export async function readSegmentation(file: File, state) { } export async function loadSegmentation(arrayBuffer: ArrayBuffer, state) { - const { referenceImageIds, skipOverlapping, viewportIds, segmentationId } = - state; + const { referenceImageIds, skipOverlapping, segmentationId } = state; const generateToolState = await Cornerstone3D.Segmentation.generateToolState( @@ -72,35 +84,15 @@ export async function loadSegmentation(arrayBuffer: ArrayBuffer, state) { return; } - const derivedSegmentationImages = - await imageLoader.createAndCacheDerivedLabelmapImages( - referenceImageIds - ); - - const derivedSegmentationImageIds = derivedSegmentationImages.map( - image => image.imageId - ); + await createSegmentation(state); - csToolsSegmentation.addSegmentations([ - { - segmentationId, - representation: { - type: cornerstoneTools.Enums.SegmentationRepresentations - .Labelmap, - data: { - imageIds: derivedSegmentationImageIds - } - } - } - ]); - - const segMap = { - [viewportIds[0]]: [{ segmentationId }], - [viewportIds[1]]: [{ segmentationId }], - [viewportIds[2]]: [{ segmentationId }] - }; + const segmentation = + csToolsSegmentation.state.getSegmentation(segmentationId); - await csToolsSegmentation.addLabelmapRepresentationToViewportMap(segMap); + const { imageIds } = segmentation.representationData.Labelmap; + const derivedSegmentationImages = imageIds.map(imageId => + cache.getImage(imageId) + ); const volumeScalarData = new Uint8Array( generateToolState.labelmapBufferArray[0] diff --git a/utils/ExampleRunner/template-config.js b/utils/ExampleRunner/template-config.js index 032ad27db..a5a16638c 100644 --- a/utils/ExampleRunner/template-config.js +++ b/utils/ExampleRunner/template-config.js @@ -21,7 +21,7 @@ const rspack = require('@rspack/core'); module.exports = { mode: 'development', - devtool: 'source-map', + devtool: 'eval-source-map', plugins: [ new rspack.HtmlRspackPlugin({ template: '${root.replace(/\\/g, '/')}/utils/ExampleRunner/template.html',