From c6b28654b507981d1dc5038b4f8a869ed53470fe Mon Sep 17 00:00:00 2001 From: Joe Boccanfuso <109477394+jbocce@users.noreply.github.com> Date: Fri, 16 May 2025 13:33:57 -0400 Subject: [PATCH] fix(segmentation): segmentation stats calculations were not being done on a subsequent navigation to a mode (#5046) --- extensions/cornerstone/src/index.tsx | 20 ++++--- extensions/cornerstone/src/init.tsx | 57 ------------------ .../utils/setUpSegmentationEventHandlers.ts | 60 +++++++++++++++++++ 3 files changed, 72 insertions(+), 65 deletions(-) create mode 100644 extensions/cornerstone/src/utils/setUpSegmentationEventHandlers.ts diff --git a/extensions/cornerstone/src/index.tsx b/extensions/cornerstone/src/index.tsx index 9f3ccc943..bcc6f785a 100644 --- a/extensions/cornerstone/src/index.tsx +++ b/extensions/cornerstone/src/index.tsx @@ -56,6 +56,7 @@ import { StudySummaryFromMetadata } from './components/StudySummaryFromMetadata' import CornerstoneViewportDownloadForm from './utils/CornerstoneViewportDownloadForm'; import utils from './utils'; import { useMeasurementTracking } from './hooks/useMeasurementTracking'; +import { setUpSegmentationEventHandlers } from './utils/setUpSegmentationEventHandlers'; export * from './components'; const { imageRetrieveMetadataProvider } = cornerstone.utilities; @@ -91,9 +92,16 @@ const cornerstoneExtension: Types.Extensions.Extension = { */ id, - onModeEnter: ({ servicesManager }: withAppTypes): void => { + onModeEnter: ({ servicesManager, commandsManager }: withAppTypes): void => { const { cornerstoneViewportService, toolbarService, segmentationService } = servicesManager.services; + + const { unsubscriptions: segmentationUnsubscriptions } = setUpSegmentationEventHandlers({ + servicesManager, + commandsManager, + }); + unsubscriptions.push(...segmentationUnsubscriptions); + toolbarService.registerEventForToolbarUpdate(cornerstoneViewportService, [ cornerstoneViewportService.EVENTS.VIEWPORT_DATA_CHANGED, ]); @@ -144,6 +152,8 @@ const cornerstoneExtension: Types.Extensions.Extension = { segmentationService.removeAllSegmentations(); unsubscriptions.forEach(unsubscribe => unsubscribe()); + // Clear the unsubscriptions + unsubscriptions.length = 0; }, /** @@ -163,13 +173,7 @@ const cornerstoneExtension: Types.Extensions.Extension = { const { syncGroupService } = servicesManager.services; syncGroupService.registerCustomSynchronizer('frameview', createFrameViewSynchronizer); - const initResult = await init.call(this, props); - - unsubscriptions.push(...initResult.unsubscriptions); - - return { - ...initResult, - }; + await init.call(this, props); }, getToolbarModule, getHangingProtocolModule, diff --git a/extensions/cornerstone/src/init.tsx b/extensions/cornerstone/src/init.tsx index a3b12ee74..4b73e8cd9 100644 --- a/extensions/cornerstone/src/init.tsx +++ b/extensions/cornerstone/src/init.tsx @@ -39,10 +39,6 @@ import { useLutPresentationStore } from './stores/useLutPresentationStore'; import { usePositionPresentationStore } from './stores/usePositionPresentationStore'; import { useSegmentationPresentationStore } from './stores/useSegmentationPresentationStore'; import { imageRetrieveMetadataProvider } from '@cornerstonejs/core/utilities'; -import { - setupSegmentationDataModifiedHandler, - setupSegmentationModifiedHandler, -} from './utils/segmentationHandlers'; const { registerColormap } = csUtilities.colormap; @@ -199,18 +195,6 @@ export default async function init({ }); }); - // Setup segmentation event handlers - const { unsubscribe: unsubscribeSegmentationDataModifiedHandler } = - setupSegmentationDataModifiedHandler({ - segmentationService, - customizationService, - commandsManager, - }); - - const { unsubscribe: unsubscribeSegmentationModifiedHandler } = setupSegmentationModifiedHandler({ - segmentationService, - }); - // When a custom image load is performed, update the relevant viewports hangingProtocolService.subscribe( hangingProtocolService.EVENTS.CUSTOM_IMAGE_LOAD_PERFORMED, @@ -317,47 +301,6 @@ export default async function init({ // Call this function when initializing initializeWebWorkerProgressHandler(servicesManager.services.uiNotificationService); - - const { unsubscribe: unsubscribeSegmentationCreated } = segmentationService.subscribe( - segmentationService.EVENTS.SEGMENTATION_ADDED, - evt => { - const { segmentationId } = evt; - const displaySet = displaySetService.getDisplaySetByUID(segmentationId); - if (displaySet) { - return; - } - - const segmentation = segmentationService.getSegmentation(segmentationId); - const label = segmentation.cachedStats.info; - const imageIds = segmentation.representationData.Labelmap.imageIds; - - // Create a display set for the segmentation - const segmentationDisplaySet = { - displaySetInstanceUID: segmentationId, - SOPClassUID: '1.2.840.10008.5.1.4.1.1.66.4', - SOPClassHandlerId: '@ohif/extension-cornerstone-dicom-seg.sopClassHandlerModule.dicom-seg', - SeriesDescription: label, - Modality: 'SEG', - numImageFrames: imageIds.length, - imageIds, - isOverlayDisplaySet: true, - label, - madeInClient: true, - segmentationId: segmentationId, - isDerived: true, - }; - - displaySetService.addDisplaySets(segmentationDisplaySet); - } - ); - - const unsubscriptions = [ - unsubscribeSegmentationDataModifiedHandler, - unsubscribeSegmentationModifiedHandler, - unsubscribeSegmentationCreated, - ]; - - return { unsubscriptions }; } function initializeWebWorkerProgressHandler(uiNotificationService) { diff --git a/extensions/cornerstone/src/utils/setUpSegmentationEventHandlers.ts b/extensions/cornerstone/src/utils/setUpSegmentationEventHandlers.ts new file mode 100644 index 000000000..678ce2229 --- /dev/null +++ b/extensions/cornerstone/src/utils/setUpSegmentationEventHandlers.ts @@ -0,0 +1,60 @@ +import { + setupSegmentationDataModifiedHandler, + setupSegmentationModifiedHandler, +} from './segmentationHandlers'; + +export const setUpSegmentationEventHandlers = ({ servicesManager, commandsManager }) => { + const { segmentationService, customizationService, displaySetService } = servicesManager.services; + + const { unsubscribe: unsubscribeSegmentationDataModifiedHandler } = + setupSegmentationDataModifiedHandler({ + segmentationService, + customizationService, + commandsManager, + }); + + const { unsubscribe: unsubscribeSegmentationModifiedHandler } = setupSegmentationModifiedHandler({ + segmentationService, + }); + + const { unsubscribe: unsubscribeSegmentationCreated } = segmentationService.subscribe( + segmentationService.EVENTS.SEGMENTATION_ADDED, + evt => { + const { segmentationId } = evt; + const displaySet = displaySetService.getDisplaySetByUID(segmentationId); + if (displaySet) { + return; + } + + const segmentation = segmentationService.getSegmentation(segmentationId); + const label = segmentation.cachedStats.info; + const imageIds = segmentation.representationData.Labelmap.imageIds; + + // Create a display set for the segmentation + const segmentationDisplaySet = { + displaySetInstanceUID: segmentationId, + SOPClassUID: '1.2.840.10008.5.1.4.1.1.66.4', + SOPClassHandlerId: '@ohif/extension-cornerstone-dicom-seg.sopClassHandlerModule.dicom-seg', + SeriesDescription: label, + Modality: 'SEG', + numImageFrames: imageIds.length, + imageIds, + isOverlayDisplaySet: true, + label, + madeInClient: true, + segmentationId: segmentationId, + isDerived: true, + }; + + displaySetService.addDisplaySets(segmentationDisplaySet); + } + ); + + const unsubscriptions = [ + unsubscribeSegmentationDataModifiedHandler, + unsubscribeSegmentationModifiedHandler, + unsubscribeSegmentationCreated, + ]; + + return { unsubscriptions }; +};