From 6339cf8e5f24702f86d7bbc73df4716b4a6d9830 Mon Sep 17 00:00:00 2001 From: scouser Date: Fri, 14 Feb 2025 12:37:36 +0530 Subject: [PATCH 1/6] initial commit for fixing video segmentations --- .../tools/examples/videoSegmentation/index.ts | 4 +- .../segmentation/imageChangeEventListener.ts | 189 +++++++++--------- .../segmentation/SegmentationStateManager.ts | 39 ++-- 3 files changed, 121 insertions(+), 111 deletions(-) diff --git a/packages/tools/examples/videoSegmentation/index.ts b/packages/tools/examples/videoSegmentation/index.ts index 08839726f..2aa67f15a 100644 --- a/packages/tools/examples/videoSegmentation/index.ts +++ b/packages/tools/examples/videoSegmentation/index.ts @@ -223,8 +223,8 @@ async function run() { // We need the map on all image ids const allImageIds = viewport.getImageIds(); const firstImage = allImageIds[0]; - const segImages = await imageLoader.createAndCacheDerivedImages( - [firstImage], + const segImages = await imageLoader.createAndCacheDerivedLabelmapImages( + allImageIds, { skipCreateBuffer: true, onCacheAdd: csUtils.VoxelManager.addInstanceToImage, diff --git a/packages/tools/src/eventListeners/segmentation/imageChangeEventListener.ts b/packages/tools/src/eventListeners/segmentation/imageChangeEventListener.ts index 20f0ac570..d3328e801 100644 --- a/packages/tools/src/eventListeners/segmentation/imageChangeEventListener.ts +++ b/packages/tools/src/eventListeners/segmentation/imageChangeEventListener.ts @@ -110,22 +110,22 @@ function _imageChangeEventListener(evt) { // is there any extra actor that needs to be removed // or any actor that needs to be added (which it is added later down), but remove // it here if it is not needed - labelmapActors.forEach((actor) => { - // if cannot find a representation for this actor means it has stuck around - // form previous renderings and should be removed - const validActor = labelmapRepresentations.find((representation) => { - const derivedImageId = getCurrentLabelmapImageIdForViewport( - viewportId, - representation.segmentationId - ); - - return derivedImageId === actor.referencedId; - }); - - if (!validActor) { - viewport.removeActors([actor.uid]); - } - }); + // labelmapActors.forEach((actor) => { + // // if cannot find a representation for this actor means it has stuck around + // // form previous renderings and should be removed + // const validActor = labelmapRepresentations.find((representation) => { + // const derivedImageId = getCurrentLabelmapImageIdForViewport( + // viewportId, + // representation.segmentationId + // ); + + // return derivedImageId === actor.referencedId; + // }); + + // if (!validActor) { + // viewport.removeActors([actor.uid]); + // } + // }); labelmapRepresentations.forEach((representation) => { const { segmentationId } = representation; @@ -149,85 +149,86 @@ function _imageChangeEventListener(evt) { } // re-use the old labelmap actor for the new image labelmap for speed and memory - const segmentationActorInput = actors.find( - (actor) => actor.referencedId === derivedImageId - ); - - if (!segmentationActorInput) { - // i guess we need to create here - const { dimensions, spacing, direction } = - viewport.getImageDataMetadata(derivedImage); - - const currentImage = - cache.getImage(currentImageId) || - ({ - imageId: currentImageId, - } as Types.IImage); - - const { origin: currentOrigin } = - viewport.getImageDataMetadata(currentImage); - - // IMPORTANT: We need to make sure that the origin of the segmentation - // is the same as the current image origin. This is because due to some - // floating point precision issues, when coming from volume to stack - // the origin of the segmentation can be slightly different from the - // current image origin. This can cause the segmentation to be rendered - // in the wrong location. - // Todo: This will not work for segmentations that are not in the same frame - // of reference or derived from the same image. This can happen when we have - // a segmentation that happens to exist in the same space as the image but is - // not derived from it. We need to find a way to handle this case, but don't think - // it makes sense to do it for the stack viewport, as the volume viewport is designed to handle this case. - const originToUse = currentOrigin; - const constructor = derivedImage.voxelManager.getConstructor(); - const newPixelData = derivedImage.voxelManager.getScalarData(); - - const scalarArray = vtkDataArray.newInstance({ - name: 'Pixels', - numberOfComponents: 1, - // @ts-expect-error - values: new constructor(newPixelData), - }); - - const imageData = vtkImageData.newInstance(); - - imageData.setDimensions(dimensions[0], dimensions[1], 1); - imageData.setSpacing(spacing); - imageData.setDirection(direction); - imageData.setOrigin(originToUse); - imageData.getPointData().setScalars(scalarArray); - imageData.modified(); - - viewport.addImages([ - { - imageId: derivedImageId, - representationUID: `${segmentationId}-${SegmentationRepresentations.Labelmap}`, - callback: ({ imageActor }) => { - imageActor.getMapper().setInputData(imageData); - }, - }, - ]); - - triggerSegmentationRender(viewportId); - return; + // there is only one actor in this case. and its referenceId does not match with derivedImageId + // in 1.0 we did not have this logic of filtering actors by their reference ids + const segmentationActorInput = actors.find((actor) => actor); + + // if (!segmentationActorInput) { + // // i guess we need to create here + // const { dimensions, spacing, direction } = + // viewport.getImageDataMetadata(derivedImage); + + // const currentImage = + // cache.getImage(currentImageId) || + // ({ + // imageId: currentImageId, + // } as Types.IImage); + + // const { origin: currentOrigin } = + // viewport.getImageDataMetadata(currentImage); + + // // IMPORTANT: We need to make sure that the origin of the segmentation + // // is the same as the current image origin. This is because due to some + // // floating point precision issues, when coming from volume to stack + // // the origin of the segmentation can be slightly different from the + // // current image origin. This can cause the segmentation to be rendered + // // in the wrong location. + // // Todo: This will not work for segmentations that are not in the same frame + // // of reference or derived from the same image. This can happen when we have + // // a segmentation that happens to exist in the same space as the image but is + // // not derived from it. We need to find a way to handle this case, but don't think + // // it makes sense to do it for the stack viewport, as the volume viewport is designed to handle this case. + // const originToUse = currentOrigin; + // const constructor = derivedImage.voxelManager.getConstructor(); + // const newPixelData = derivedImage.voxelManager.getScalarData(); + + // const scalarArray = vtkDataArray.newInstance({ + // name: 'Pixels', + // numberOfComponents: 1, + // // @ts-expect-error + // values: new constructor(newPixelData), + // }); + + // const imageData = vtkImageData.newInstance(); + + // imageData.setDimensions(dimensions[0], dimensions[1], 1); + // imageData.setSpacing(spacing); + // imageData.setDirection(direction); + // imageData.setOrigin(originToUse); + // imageData.getPointData().setScalars(scalarArray); + // imageData.modified(); + + // viewport.addImages([ + // { + // imageId: derivedImageId, + // representationUID: `${segmentationId}-${SegmentationRepresentations.Labelmap}`, + // callback: ({ imageActor }) => { + // imageActor.getMapper().setInputData(imageData); + // }, + // }, + // ]); + + // triggerSegmentationRender(viewportId); + // return; + // } else { + // // if actor found + // // update the image data + + // } + + const segmentationImageData = segmentationActorInput.actor + .getMapper() + .getInputData(); + + if (segmentationImageData.setDerivedImage) { + // Update the derived image data, whether vtk or other as appropriate + // to the actor(s) displaying the data. + segmentationImageData.setDerivedImage(derivedImage); } else { - // if actor found - // update the image data - - const segmentationImageData = segmentationActorInput.actor - .getMapper() - .getInputData(); - - if (segmentationImageData.setDerivedImage) { - // Update the derived image data, whether vtk or other as appropriate - // to the actor(s) displaying the data. - segmentationImageData.setDerivedImage(derivedImage); - } else { - utilities.updateVTKImageDataWithCornerstoneImage( - segmentationImageData, - derivedImage - ); - } + utilities.updateVTKImageDataWithCornerstoneImage( + segmentationImageData, + derivedImage + ); } viewport.render(); diff --git a/packages/tools/src/stateManagement/segmentation/SegmentationStateManager.ts b/packages/tools/src/stateManagement/segmentation/SegmentationStateManager.ts index ff10b3133..c3e7c5528 100644 --- a/packages/tools/src/stateManagement/segmentation/SegmentationStateManager.ts +++ b/packages/tools/src/stateManagement/segmentation/SegmentationStateManager.ts @@ -451,21 +451,30 @@ export default class SegmentationStateManager { updateCallback ): string | undefined { const currentImageId = viewport.getCurrentImageId(); - - let viewableLabelmapImageIdFound = false; - for (const labelmapImageId of labelmapImageIds) { - const viewableImageId = viewport.isReferenceViewable( - { referencedImageId: labelmapImageId }, - { asOverlay: true } - ); - - if (viewableImageId) { - viewableLabelmapImageIdFound = true; - this._stackLabelmapImageIdReferenceMap - .get(segmentationId) - .set(currentImageId, labelmapImageId); - } - } + const allImages = viewport.getImageIds(); + + const idx = allImages.findIndex((s) => s === currentImageId); + const labelmapImageId = labelmapImageIds[idx]; + + const viewableLabelmapImageIdFound = true; + this._stackLabelmapImageIdReferenceMap + .get(segmentationId) + .set(currentImageId, labelmapImageId); + + // let viewableLabelmapImageIdFound = false; + // for (const labelmapImageId of labelmapImageIds) { + // const viewableImageId = viewport.isReferenceViewable( + // { referencedImageId: labelmapImageId }, + // { asOverlay: true } + // ); + + // if (viewableImageId) { + // viewableLabelmapImageIdFound = true; + // this._stackLabelmapImageIdReferenceMap + // .get(segmentationId) + // .set(currentImageId, labelmapImageId); + // } + // } if (updateCallback) { updateCallback(viewport, segmentationId, labelmapImageIds); From 8355ad4422716259465925ecb009c9f4ed855d0d Mon Sep 17 00:00:00 2001 From: minimal-scouser Date: Tue, 4 Mar 2025 14:29:07 +0530 Subject: [PATCH 2/6] revert previous changes --- .../tools/examples/videoSegmentation/index.ts | 11 +- .../segmentation/imageChangeEventListener.ts | 189 +++++++++--------- .../segmentation/SegmentationStateManager.ts | 39 ++-- 3 files changed, 115 insertions(+), 124 deletions(-) diff --git a/packages/tools/examples/videoSegmentation/index.ts b/packages/tools/examples/videoSegmentation/index.ts index 2aa67f15a..a8dceb0e1 100644 --- a/packages/tools/examples/videoSegmentation/index.ts +++ b/packages/tools/examples/videoSegmentation/index.ts @@ -165,9 +165,10 @@ function setupTools(toolGroupId) { preview: { enabled: true, }, - strategySpecificConfiguration: { - useCenterSegmentIndex: true, - THRESHOLD: { isDynamic: true, dynamicRadius: 3 }, + useCenterSegmentIndex: true, + threshold: { + isDynamic: true, + dynamicRadius: 3, }, } ); @@ -223,8 +224,8 @@ async function run() { // We need the map on all image ids const allImageIds = viewport.getImageIds(); const firstImage = allImageIds[0]; - const segImages = await imageLoader.createAndCacheDerivedLabelmapImages( - allImageIds, + const segImages = await imageLoader.createAndCacheDerivedImages( + [firstImage], { skipCreateBuffer: true, onCacheAdd: csUtils.VoxelManager.addInstanceToImage, diff --git a/packages/tools/src/eventListeners/segmentation/imageChangeEventListener.ts b/packages/tools/src/eventListeners/segmentation/imageChangeEventListener.ts index d3328e801..20f0ac570 100644 --- a/packages/tools/src/eventListeners/segmentation/imageChangeEventListener.ts +++ b/packages/tools/src/eventListeners/segmentation/imageChangeEventListener.ts @@ -110,22 +110,22 @@ function _imageChangeEventListener(evt) { // is there any extra actor that needs to be removed // or any actor that needs to be added (which it is added later down), but remove // it here if it is not needed - // labelmapActors.forEach((actor) => { - // // if cannot find a representation for this actor means it has stuck around - // // form previous renderings and should be removed - // const validActor = labelmapRepresentations.find((representation) => { - // const derivedImageId = getCurrentLabelmapImageIdForViewport( - // viewportId, - // representation.segmentationId - // ); - - // return derivedImageId === actor.referencedId; - // }); - - // if (!validActor) { - // viewport.removeActors([actor.uid]); - // } - // }); + labelmapActors.forEach((actor) => { + // if cannot find a representation for this actor means it has stuck around + // form previous renderings and should be removed + const validActor = labelmapRepresentations.find((representation) => { + const derivedImageId = getCurrentLabelmapImageIdForViewport( + viewportId, + representation.segmentationId + ); + + return derivedImageId === actor.referencedId; + }); + + if (!validActor) { + viewport.removeActors([actor.uid]); + } + }); labelmapRepresentations.forEach((representation) => { const { segmentationId } = representation; @@ -149,86 +149,85 @@ function _imageChangeEventListener(evt) { } // re-use the old labelmap actor for the new image labelmap for speed and memory - // there is only one actor in this case. and its referenceId does not match with derivedImageId - // in 1.0 we did not have this logic of filtering actors by their reference ids - const segmentationActorInput = actors.find((actor) => actor); - - // if (!segmentationActorInput) { - // // i guess we need to create here - // const { dimensions, spacing, direction } = - // viewport.getImageDataMetadata(derivedImage); - - // const currentImage = - // cache.getImage(currentImageId) || - // ({ - // imageId: currentImageId, - // } as Types.IImage); - - // const { origin: currentOrigin } = - // viewport.getImageDataMetadata(currentImage); - - // // IMPORTANT: We need to make sure that the origin of the segmentation - // // is the same as the current image origin. This is because due to some - // // floating point precision issues, when coming from volume to stack - // // the origin of the segmentation can be slightly different from the - // // current image origin. This can cause the segmentation to be rendered - // // in the wrong location. - // // Todo: This will not work for segmentations that are not in the same frame - // // of reference or derived from the same image. This can happen when we have - // // a segmentation that happens to exist in the same space as the image but is - // // not derived from it. We need to find a way to handle this case, but don't think - // // it makes sense to do it for the stack viewport, as the volume viewport is designed to handle this case. - // const originToUse = currentOrigin; - // const constructor = derivedImage.voxelManager.getConstructor(); - // const newPixelData = derivedImage.voxelManager.getScalarData(); - - // const scalarArray = vtkDataArray.newInstance({ - // name: 'Pixels', - // numberOfComponents: 1, - // // @ts-expect-error - // values: new constructor(newPixelData), - // }); - - // const imageData = vtkImageData.newInstance(); - - // imageData.setDimensions(dimensions[0], dimensions[1], 1); - // imageData.setSpacing(spacing); - // imageData.setDirection(direction); - // imageData.setOrigin(originToUse); - // imageData.getPointData().setScalars(scalarArray); - // imageData.modified(); - - // viewport.addImages([ - // { - // imageId: derivedImageId, - // representationUID: `${segmentationId}-${SegmentationRepresentations.Labelmap}`, - // callback: ({ imageActor }) => { - // imageActor.getMapper().setInputData(imageData); - // }, - // }, - // ]); - - // triggerSegmentationRender(viewportId); - // return; - // } else { - // // if actor found - // // update the image data - - // } - - const segmentationImageData = segmentationActorInput.actor - .getMapper() - .getInputData(); - - if (segmentationImageData.setDerivedImage) { - // Update the derived image data, whether vtk or other as appropriate - // to the actor(s) displaying the data. - segmentationImageData.setDerivedImage(derivedImage); + const segmentationActorInput = actors.find( + (actor) => actor.referencedId === derivedImageId + ); + + if (!segmentationActorInput) { + // i guess we need to create here + const { dimensions, spacing, direction } = + viewport.getImageDataMetadata(derivedImage); + + const currentImage = + cache.getImage(currentImageId) || + ({ + imageId: currentImageId, + } as Types.IImage); + + const { origin: currentOrigin } = + viewport.getImageDataMetadata(currentImage); + + // IMPORTANT: We need to make sure that the origin of the segmentation + // is the same as the current image origin. This is because due to some + // floating point precision issues, when coming from volume to stack + // the origin of the segmentation can be slightly different from the + // current image origin. This can cause the segmentation to be rendered + // in the wrong location. + // Todo: This will not work for segmentations that are not in the same frame + // of reference or derived from the same image. This can happen when we have + // a segmentation that happens to exist in the same space as the image but is + // not derived from it. We need to find a way to handle this case, but don't think + // it makes sense to do it for the stack viewport, as the volume viewport is designed to handle this case. + const originToUse = currentOrigin; + const constructor = derivedImage.voxelManager.getConstructor(); + const newPixelData = derivedImage.voxelManager.getScalarData(); + + const scalarArray = vtkDataArray.newInstance({ + name: 'Pixels', + numberOfComponents: 1, + // @ts-expect-error + values: new constructor(newPixelData), + }); + + const imageData = vtkImageData.newInstance(); + + imageData.setDimensions(dimensions[0], dimensions[1], 1); + imageData.setSpacing(spacing); + imageData.setDirection(direction); + imageData.setOrigin(originToUse); + imageData.getPointData().setScalars(scalarArray); + imageData.modified(); + + viewport.addImages([ + { + imageId: derivedImageId, + representationUID: `${segmentationId}-${SegmentationRepresentations.Labelmap}`, + callback: ({ imageActor }) => { + imageActor.getMapper().setInputData(imageData); + }, + }, + ]); + + triggerSegmentationRender(viewportId); + return; } else { - utilities.updateVTKImageDataWithCornerstoneImage( - segmentationImageData, - derivedImage - ); + // if actor found + // update the image data + + const segmentationImageData = segmentationActorInput.actor + .getMapper() + .getInputData(); + + if (segmentationImageData.setDerivedImage) { + // Update the derived image data, whether vtk or other as appropriate + // to the actor(s) displaying the data. + segmentationImageData.setDerivedImage(derivedImage); + } else { + utilities.updateVTKImageDataWithCornerstoneImage( + segmentationImageData, + derivedImage + ); + } } viewport.render(); diff --git a/packages/tools/src/stateManagement/segmentation/SegmentationStateManager.ts b/packages/tools/src/stateManagement/segmentation/SegmentationStateManager.ts index c3e7c5528..ff10b3133 100644 --- a/packages/tools/src/stateManagement/segmentation/SegmentationStateManager.ts +++ b/packages/tools/src/stateManagement/segmentation/SegmentationStateManager.ts @@ -451,30 +451,21 @@ export default class SegmentationStateManager { updateCallback ): string | undefined { const currentImageId = viewport.getCurrentImageId(); - const allImages = viewport.getImageIds(); - - const idx = allImages.findIndex((s) => s === currentImageId); - const labelmapImageId = labelmapImageIds[idx]; - - const viewableLabelmapImageIdFound = true; - this._stackLabelmapImageIdReferenceMap - .get(segmentationId) - .set(currentImageId, labelmapImageId); - - // let viewableLabelmapImageIdFound = false; - // for (const labelmapImageId of labelmapImageIds) { - // const viewableImageId = viewport.isReferenceViewable( - // { referencedImageId: labelmapImageId }, - // { asOverlay: true } - // ); - - // if (viewableImageId) { - // viewableLabelmapImageIdFound = true; - // this._stackLabelmapImageIdReferenceMap - // .get(segmentationId) - // .set(currentImageId, labelmapImageId); - // } - // } + + let viewableLabelmapImageIdFound = false; + for (const labelmapImageId of labelmapImageIds) { + const viewableImageId = viewport.isReferenceViewable( + { referencedImageId: labelmapImageId }, + { asOverlay: true } + ); + + if (viewableImageId) { + viewableLabelmapImageIdFound = true; + this._stackLabelmapImageIdReferenceMap + .get(segmentationId) + .set(currentImageId, labelmapImageId); + } + } if (updateCallback) { updateCallback(viewport, segmentationId, labelmapImageIds); From 67e112e245eb768a961ea9f36960fa10d389c775 Mon Sep 17 00:00:00 2001 From: minimal-scouser Date: Tue, 4 Mar 2025 14:40:51 +0530 Subject: [PATCH 3/6] add index as an argument to getDerivedImageId --- packages/core/src/loaders/imageLoader.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/src/loaders/imageLoader.ts b/packages/core/src/loaders/imageLoader.ts index dfffb13a0..2152ab9f3 100644 --- a/packages/core/src/loaders/imageLoader.ts +++ b/packages/core/src/loaders/imageLoader.ts @@ -340,7 +340,7 @@ export function createAndCacheDerivedImage( export function createAndCacheDerivedImages( referencedImageIds: string[], options: DerivedImageOptions & { - getDerivedImageId?: (referencedImageId: string) => string; + getDerivedImageId?: (referencedImageId: string, index: number) => string; targetBuffer?: { type: PixelDataTypedArrayString; }; @@ -356,7 +356,7 @@ export function createAndCacheDerivedImages( const images = referencedImageIds.map((referencedImageId, index) => { const newOptions: DerivedImageOptions = { imageId: - options?.getDerivedImageId?.(referencedImageId) || + options?.getDerivedImageId?.(referencedImageId, index) || `derived:${uuidv4()}`, ...options, }; From f19cfb4c64eb3baceb084ce56aeb7ff78a459509 Mon Sep 17 00:00:00 2001 From: minimal-scouser Date: Tue, 4 Mar 2025 14:43:28 +0530 Subject: [PATCH 4/6] fix breaking change when trying to remove actor - esp for video viewport --- packages/core/src/RenderingEngine/Viewport.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/core/src/RenderingEngine/Viewport.ts b/packages/core/src/RenderingEngine/Viewport.ts index c33ce5c25..3819d4868 100644 --- a/packages/core/src/RenderingEngine/Viewport.ts +++ b/packages/core/src/RenderingEngine/Viewport.ts @@ -539,7 +539,8 @@ class Viewport { return; } const renderer = this.getRenderer(); - renderer.removeViewProp(actorEntry.actor as vtkProp); // removeActor not implemented in vtk? + // the optional chaining is particularly for video viewports + renderer?.removeViewProp(actorEntry.actor as vtkProp); // removeActor not implemented in vtk? this._actors.delete(actorUID); } From 959ac0f7ac536ddfac1dee0f080307f1f1f3d39f Mon Sep 17 00:00:00 2001 From: minimal-scouser Date: Tue, 4 Mar 2025 15:29:34 +0530 Subject: [PATCH 5/6] use appropriate method for setting image data to a video viewport actor --- .../segmentation/imageChangeEventListener.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/tools/src/eventListeners/segmentation/imageChangeEventListener.ts b/packages/tools/src/eventListeners/segmentation/imageChangeEventListener.ts index 20f0ac570..c53fe071e 100644 --- a/packages/tools/src/eventListeners/segmentation/imageChangeEventListener.ts +++ b/packages/tools/src/eventListeners/segmentation/imageChangeEventListener.ts @@ -8,6 +8,7 @@ import { getEnabledElementByIds, cache, utilities, + VideoViewport, } from '@cornerstonejs/core'; import { triggerSegmentationRender } from '../../stateManagement/segmentation/SegmentationRenderingEngine'; import { updateLabelmapSegmentationImageReferences } from '../../stateManagement/segmentation/updateLabelmapSegmentationImageReferences'; @@ -203,7 +204,11 @@ function _imageChangeEventListener(evt) { imageId: derivedImageId, representationUID: `${segmentationId}-${SegmentationRepresentations.Labelmap}`, callback: ({ imageActor }) => { - imageActor.getMapper().setInputData(imageData); + if (viewport instanceof VideoViewport) { + imageActor.getMapper().getInputData().setDerivedImage(imageData); + } else { + imageActor.getMapper().setInputData(imageData); + } }, }, ]); From 410eaa9117029157cd19f5c3aa01c5cefe4019cb Mon Sep 17 00:00:00 2001 From: minimal-scouser Date: Tue, 4 Mar 2025 15:31:40 +0530 Subject: [PATCH 6/6] append frames to derivedImageId to comply with video viewport --- packages/tools/examples/videoSegmentation/index.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/tools/examples/videoSegmentation/index.ts b/packages/tools/examples/videoSegmentation/index.ts index a8dceb0e1..bae2980da 100644 --- a/packages/tools/examples/videoSegmentation/index.ts +++ b/packages/tools/examples/videoSegmentation/index.ts @@ -224,11 +224,14 @@ async function run() { // We need the map on all image ids const allImageIds = viewport.getImageIds(); const firstImage = allImageIds[0]; - const segImages = await imageLoader.createAndCacheDerivedImages( - [firstImage], + const segImages = await imageLoader.createAndCacheDerivedLabelmapImages( + allImageIds, { skipCreateBuffer: true, onCacheAdd: csUtils.VoxelManager.addInstanceToImage, + getDerivedImageId: (referenceImageId, index) => { + return `derived:${cornerstone.utilities.uuidv4()}/frames/${index + 1}`; + }, } );