From f1392ee18f190042648125e63d95437de479e949 Mon Sep 17 00:00:00 2001 From: scouser Date: Fri, 14 Feb 2025 12:37:36 +0530 Subject: [PATCH] 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);