Below we will review the changes to the API of the SegmentationService
SegmentationService API
Events​
SEGMENTATION_UPDATED -> SEGMENTATION_MODIFIED
Just a rename to match the cornerstone terminology
VolumeId vs SegmentationId​
Previously, we used the SegmentationId as the VolumeId for volume-based segmentations, which led to confusion and issues.
Now, we have two separate IDs: one for the segmentation and one for the volume.
segmentationService.getLabelmapVolume(segmentationId)
will return the volume associated with the segmentation.
If your code uses cache.getVolume(segmentationId)
, update it to use the new getLabelmapVolume
method.
getSegmentation(segmentationId)​
remains the same it will return the segmentation object = cornerstone segmentation object with the following properties:
/**
* Global Segmentation Data which is used for the segmentation
*/
type Segmentation = {
/** segmentation id */
segmentationId: string;
/** segmentation label */
label: string;
segments: {
[segmentIndex: number]: Segment;
};
/**
* Representations of the segmentation. Each segmentation "can" be viewed
* in various representations. For instance, if a DICOM SEG is loaded, the main
* representation is the labelmap. However, for DICOM RT the main representation
* is contours, and other representations can be derived from the contour (currently
* only labelmap representation is supported)
*/
representationData: RepresentationsData;
/**
* Segmentation level stats, Note each segment can have its own stats
* This is used for caching stats for the segmentation level
*/
cachedStats: { [key: string]: unknown };
};
export type Segment = {
/** segment index */
segmentIndex: number;
/** segment label */
label: string;
/** is segment locked for editing */
locked: boolean;
/** cached stats for the segment, e.g., pt suv mean, max etc. */
cachedStats: { [key: string]: unknown };
/** is segment active for editing, at the same time only one segment can be active for editing */
active: boolean;
};
Compared to Cornerstone3D 1.x
Previously this function was returning this
export type Segmentation = {
segmentationId: string;
type: Enums.SegmentationRepresentations;
label: string;
activeSegmentIndex: number;
segmentsLocked: Set<number>;
cachedStats: { [key: string]: number };
segmentLabels: { [key: string]: string };
representationData: SegmentationRepresentationData;
};
As you can see segmentLabels
, segmentsLocked
, activeSegmentIndex
, are all gathered under the new segments
object. We now have support for per segment cachedStats as well.
getSegmentations​
It provides all segmentations in the state. Previously, it accepted a filterNonhydrated
flag, but since we've moved away from hydration and every loaded segmentation is now hydrated by default, it returns all segmentations.
getActiveSegmentation​
After migrating to viewport-specific segmentations, different viewports can have distinct active segmentations for editing. The panel will always display the active segmentation when the active viewport changes.
Before (3.8)
// Returns full segmentation object
public getActiveSegmentation(): Segmentation {
const segmentations = this.getSegmentations();
return segmentations.find(segmentation => segmentation.isActive);
}
After (3.9)
public getActiveSegmentation(viewportId: string): Segmentation | null {
return cstSegmentation.activeSegmentation.getActiveSegmentation(viewportId);
}
Key Changes
- Viewport Specificity
- Before: Global active segmentation across all tool groups
- After: Active segmentation per viewport
- Required Parameters
- Before: No parameters needed
- After: Requires viewportId parameter
Migration Examples
Before:
// Get active segmentation
const activeSegmentation = segmentationService.getActiveSegmentation();
if (activeSegmentation) {
console.log('Active segmentation:', activeSegmentation.segmentationId);
console.log('Active segment:', activeSegmentation.activeSegmentIndex);
}
After:
// Get active segmentation for specific viewport
const activeSegmentation = segmentationService.getActiveSegmentation('viewport1');
getToolGroupIdsWithSegmentation​
is now -> getViewportIdsWithSegmentation
as you guessed
setActiveSegmentationForToolGroup​
-> setActiveSegmentation
Before (OHIF 3.8)
setActiveSegmentationForToolGroup(
segmentationId: string,
toolGroupId?: string,
suppressEvents?: boolean
): void
After (OHIF 3.9)
setActiveSegmentation(
viewportId: string,
segmentationId: string
): void
Migration Examples
-
Basic Usage Update
// Before - OHIF 3.8
segmentationService.setActiveSegmentationForToolGroup(
segmentationId,
toolGroupId
);
// After - OHIF 3.9
segmentationService.setActiveSegmentation(
viewportId,
segmentationId
);
addSegment​
The addSegment
method in OHIF 3.9 has been updated to handle segmentation properties in a viewport-centric way, removing tool group dependencies and simplifying the configuration structure.
Before (OHIF 3.8)
addSegment(
segmentationId: string,
config: {
segmentIndex?: number;
toolGroupId?: string;
properties?: {
label?: string;
color?: ohifTypes.RGB;
opacity?: number;
visibility?: boolean;
isLocked?: boolean;
active?: boolean;
};
}
): void
After (OHIF 3.9)
addSegment(
segmentationId: string,
config: {
segmentIndex?: number;
label?: string;
isLocked?: boolean;
active?: boolean;
color?: csTypes.Color;
visibility?: boolean;
}
): void
Key Changes
- Configuration Structure
- Removed double nested
properties
object - Configuration options now at top level
- Removed
toolGroupId
parameter - Removed
opacity
parameter (now part of color)
- Removed double nested
- Segment Index Generation
- Changed from length-based to max-value-based indexing
- More reliable for non-sequential segment indices
- Color Handling
- Color now includes alpha channel (opacity)
- Applied to all relevant viewports automatically
Migration Examples
-
Basic Segment Creation
// Before - OHIF 3.8
segmentationService.addSegment(segmentationId, {
properties: {
label: 'Segment 1'
}
});
// After - OHIF 3.9
segmentationService.addSegment(segmentationId, {
label: 'Segment 1'
}); -
Creating Segment with Color
// Before - OHIF 3.8
segmentationService.addSegment(segmentationId, {
properties: {
color: [255, 0, 0],
opacity: 255
}
});
// After - OHIF 3.9
segmentationService.addSegment(segmentationId, {
color: [255, 0, 0, 255] // RGB + Alpha
}); -
Setting Visibility and Lock Status
// Before - OHIF 3.8
segmentationService.addSegment(segmentationId, {
toolGroupId: 'myToolGroup',
properties: {
visibility: true,
isLocked: true
}
});
// After - OHIF 3.9
segmentationService.addSegment(segmentationId, {
visibility: true,
isLocked: true
}); -
Complete Configuration Example
// Before - OHIF 3.8
segmentationService.addSegment(segmentationId, {
segmentIndex: 1,
toolGroupId: 'myToolGroup',
properties: {
label: 'Tumor',
color: [255, 0, 0],
opacity: 200,
visibility: true,
isLocked: false,
active: true
}
});
// After - OHIF 3.9
segmentationService.addSegment(segmentationId, {
segmentIndex: 1,
label: 'Tumor',
color: [255, 0, 0, 200], // RGB + Alpha
visibility: true,
isLocked: false,
active: true
});
Important Changes
-
Tool Group Removal
// Before - OHIF 3.8
segmentationService.addSegment(segmentationId, {
toolGroupId: 'myToolGroup'
// ... other properties
});
// After - OHIF 3.9
// No tool group needed - automatically applies to all relevant viewports
segmentationService.addSegment(segmentationId, {
// ... properties
}); -
Segment Index Generation
// Before - OHIF 3.8
// Used array length
segmentIndex = segmentation.segments.length === 0 ? 1 : segmentation.segments.length;
// After - OHIF 3.9
// Uses highest existing index + 1
segmentIndex = Math.max(...Object.keys(csSegmentation.segments).map(Number)) + 1; -
Color and Opacity
// Before - OHIF 3.8
segmentationService.addSegment(segmentationId, {
properties: {
color: [255, 0, 0],
opacity: 200
}
});
// After - OHIF 3.9
segmentationService.addSegment(segmentationId, {
color: [255, 0, 0, 200] // Combined color and opacity
});
getActiveSegment​
now requires viewportId, since we have moved away from global active segmentation to viewport specific one
API Changes
// Before
getActiveSegment(): Segment
// After
getActiveSegment(viewportId: string): Segment | null