fix(segmentation): Allow for manually added label map and contour segmentations to be used as viewport data overlays. (#5562)

This commit is contained in:
Joe Boccanfuso 2025-11-13 07:12:28 -05:00 committed by GitHub
parent 5c44fe06dc
commit 02f6744dab
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 25 additions and 15 deletions

View File

@ -233,7 +233,7 @@ class CornerstoneCacheService {
for (const displaySet of displaySets) {
const { Modality } = displaySet;
const isParametricMap = Modality === 'PMAP';
const isSeg = Modality === 'SEG';
const isSegOrRtstruct = Modality === 'SEG' || Modality === 'RTSTRUCT';
// Don't create volumes for the displaySets that have custom load
// function (e.g., SEG, RT, since they rely on the reference volumes
@ -276,7 +276,7 @@ class CornerstoneCacheService {
// Parametric maps do not have image ids but they already have volume data
// therefore a new volume should not be created.
if (!isParametricMap && !isSeg && (!volumeImageIds || !volume)) {
if (!isParametricMap && !isSegOrRtstruct && (!volumeImageIds || !volume)) {
volumeImageIds = this._getCornerstoneVolumeImageIds(displaySet, dataSource);
volume = await volumeLoader.createAndCacheVolume(volumeId, {

View File

@ -125,6 +125,7 @@ describe('setUpSegmentationEventHandlers', () => {
it('should create and add display set when segmentation is added and no displaySet exists', () => {
const mockSegmentation = {
label: 'Test Segmentation Label',
cachedStats: {
info: 'Test Segmentation Label',
},
@ -151,12 +152,12 @@ describe('setUpSegmentationEventHandlers', () => {
displaySetInstanceUID: 'test-segmentation-id',
SOPClassUID: '1.2.840.10008.5.1.4.1.1.66.4',
SOPClassHandlerId: '@ohif/extension-cornerstone-dicom-seg.sopClassHandlerModule.dicom-seg',
SeriesDescription: mockSegmentation.cachedStats.info,
SeriesDescription: mockSegmentation.label,
Modality: 'SEG',
numImageFrames: mockSegmentation.representationData.Labelmap.imageIds.length,
imageIds: mockSegmentation.representationData.Labelmap.imageIds,
isOverlayDisplaySet: true,
label: mockSegmentation.cachedStats.info,
label: mockSegmentation.label,
madeInClient: true,
segmentationId: 'test-segmentation-id',
isDerived: true,
@ -165,6 +166,7 @@ describe('setUpSegmentationEventHandlers', () => {
it('should handle displaySet undefined when segmentation is added', () => {
const mockSegmentation = {
label: 'Test Segmentation Label',
cachedStats: {
info: 'Test Segmentation Label',
},
@ -190,12 +192,12 @@ describe('setUpSegmentationEventHandlers', () => {
displaySetInstanceUID: 'test-segmentation-id',
SOPClassUID: '1.2.840.10008.5.1.4.1.1.66.4',
SOPClassHandlerId: '@ohif/extension-cornerstone-dicom-seg.sopClassHandlerModule.dicom-seg',
SeriesDescription: mockSegmentation.cachedStats.info,
SeriesDescription: mockSegmentation.label,
Modality: 'SEG',
numImageFrames: mockSegmentation.representationData.Labelmap.imageIds.length,
imageIds: mockSegmentation.representationData.Labelmap.imageIds,
isOverlayDisplaySet: true,
label: mockSegmentation.cachedStats.info,
label: mockSegmentation.label,
madeInClient: true,
segmentationId: 'test-segmentation-id',
isDerived: true,
@ -204,6 +206,7 @@ describe('setUpSegmentationEventHandlers', () => {
it('should handle empty imageIds array', () => {
const mockSegmentation = {
label: 'Empty Segmentation',
cachedStats: {
info: 'Empty Segmentation',
},
@ -228,12 +231,12 @@ describe('setUpSegmentationEventHandlers', () => {
displaySetInstanceUID: 'empty-segmentation-id',
SOPClassUID: '1.2.840.10008.5.1.4.1.1.66.4',
SOPClassHandlerId: '@ohif/extension-cornerstone-dicom-seg.sopClassHandlerModule.dicom-seg',
SeriesDescription: mockSegmentation.cachedStats.info,
SeriesDescription: mockSegmentation.label,
Modality: 'SEG',
numImageFrames: 0,
imageIds: [],
isOverlayDisplaySet: true,
label: mockSegmentation.cachedStats.info,
label: mockSegmentation.label,
madeInClient: true,
segmentationId: 'empty-segmentation-id',
isDerived: true,
@ -242,6 +245,7 @@ describe('setUpSegmentationEventHandlers', () => {
it('should handle different segmentation label values', () => {
const mockSegmentation = {
label: 'Custom Label Text',
cachedStats: {
info: 'Custom Label Text',
},
@ -280,6 +284,7 @@ describe('setUpSegmentationEventHandlers', () => {
it('should handle multiple segmentation events', () => {
const mockSegmentation1 = {
label: 'Segmentation 1',
cachedStats: {
info: 'Segmentation 1',
},
@ -291,6 +296,7 @@ describe('setUpSegmentationEventHandlers', () => {
};
const mockSegmentation2 = {
label: 'Segmentation 2',
cachedStats: {
info: 'Segmentation 2',
},
@ -318,12 +324,12 @@ describe('setUpSegmentationEventHandlers', () => {
displaySetInstanceUID: 'segmentation-1',
SOPClassUID: '1.2.840.10008.5.1.4.1.1.66.4',
SOPClassHandlerId: '@ohif/extension-cornerstone-dicom-seg.sopClassHandlerModule.dicom-seg',
SeriesDescription: mockSegmentation1.cachedStats.info,
SeriesDescription: mockSegmentation1.label,
Modality: 'SEG',
numImageFrames: 1,
imageIds: mockSegmentation1.representationData.Labelmap.imageIds,
isOverlayDisplaySet: true,
label: mockSegmentation1.cachedStats.info,
label: mockSegmentation1.label,
madeInClient: true,
segmentationId: 'segmentation-1',
isDerived: true,
@ -332,12 +338,12 @@ describe('setUpSegmentationEventHandlers', () => {
displaySetInstanceUID: 'segmentation-2',
SOPClassUID: '1.2.840.10008.5.1.4.1.1.66.4',
SOPClassHandlerId: '@ohif/extension-cornerstone-dicom-seg.sopClassHandlerModule.dicom-seg',
SeriesDescription: mockSegmentation2.cachedStats.info,
SeriesDescription: mockSegmentation2.label,
Modality: 'SEG',
numImageFrames: 2,
imageIds: mockSegmentation2.representationData.Labelmap.imageIds,
isOverlayDisplaySet: true,
label: mockSegmentation2.cachedStats.info,
label: mockSegmentation2.label,
madeInClient: true,
segmentationId: 'segmentation-2',
isDerived: true,

View File

@ -1,3 +1,5 @@
import { Enums as csToolsEnums } from '@cornerstonejs/tools';
import {
setUpSelectedSegmentationsForViewportHandler,
setupSegmentationDataModifiedHandler,
@ -28,7 +30,7 @@ export const setUpSegmentationEventHandlers = ({ servicesManager, commandsManage
}
const segmentation = segmentationService.getSegmentation(segmentationId);
const label = segmentation.cachedStats.info;
const label = segmentation.label;
const imageIds =
segmentation.representationData?.Labelmap?.imageIds ??
segmentation.representationData?.Contour?.imageIds;
@ -39,7 +41,9 @@ export const setUpSegmentationEventHandlers = ({ servicesManager, commandsManage
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',
Modality: segmentation.representationData[csToolsEnums.SegmentationRepresentations.Contour]
? 'RTSTRUCT'
: 'SEG',
numImageFrames: imageIds.length,
imageIds,
isOverlayDisplaySet: true,

View File

@ -239,8 +239,8 @@ function modeFactory({ modeConfiguration }) {
leftPanels: [ohif.leftPanel],
leftPanelResizable: true,
rightPanels: [
cornerstone.contourSegmentationPanel,
cornerstone.labelMapSegmentationPanel,
cornerstone.contourSegmentationPanel,
],
rightPanelResizable: true,
// leftPanelClosed: true,