@cornerstonejs/tools
triggerAnnotationRenderForViewportIds
Now only requires viewportIds and doesn't need renderingEngine anymore
triggerAnnotationRenderForViewportIds(renderingEngine, viewportIds) ---> triggerAnnotationRenderForViewportIds(viewportIds)
Details
Why?
Since there is one rendering engine per viewport, there is no need to pass the rendering engine as an argument.Tools
StackScrollMouseWheelTool -> StackScrollTool
We've decoupled the Mouse Wheel from the tool itself, allowing it to be applied as a binding similar to other mouse bindings.
This change offers several advantages:
- It can be combined with other mouse bindings
- It can be paired with keyboard bindings
- Before 📦
- After 🚀🚀
cornerstoneTools.addTool(StackScrollMouseWheelTool);
toolGroup.addTool(StackScrollMouseWheelTool.toolName);
toolGroup.setToolActive(StackScrollMouseWheelTool.toolName);
cornerstoneTools.addTool(StackScrollTool);
toolGroup.addTool(StackScrollTool.toolName);
toolGroup.setToolActive(StackScrollTool.toolName, {
bindings: [
{
mouseButton: MouseBindings.Wheel,
},
],
});
BaseTool
The getTargetVolumeId
method has been removed in favor of getTargetId
, and getTargetIdImage
has been renamed to getTargetImageData
to make it more clear that it is an image data.
Usage Example
- Before 📦
- After 🚀
const volumeId = this.getTargetVolumeId(viewport);
const imageData = this.getTargetIdImage(targetId, renderingEngine);
const imageData = this.getTargetImageData(targetId);
New Segmentation Model
We have a new segmentation model that is more flexible and easier to use.
Same Terminology, Different Architecture
In Cornerstone3D version 2, we've made significant architectural changes to our segmentation model while maintaining familiar terminology. This redesign aims to provide a more flexible and intuitive approach to working with segmentations across different viewports. Here are the key changes and the reasons behind them:
-
Viewport-Specific, Not Tool Group-Based:
- Old: Segmentations were tied to tool groups, which typically consist of multiple viewports. This created complications when users wanted to add segmentations to some viewports but not others within the same tool group.
- New: Segmentations are now viewport-specific. Instead of adding or removing representations to a tool group, users can add them directly to viewports. This provides much finer control over what each viewport renders.
- Why: We discovered that tying rendering to a tool group is not an effective approach. It often necessitated creating an extra tool group for a specific viewport to customize or prevent rendering.
-
Simplified Identification of Segmentation Representations:
- Old: Required a unique segmentationRepresentationUID for identification.
- New: Segmentation representations are identified by a combination of
segmentationId
and representationtype
. This allows each viewport to have different representations of the same segmentation. - Why: This simplification makes it easier to manage and reference segmentation representations across different viewports.
-
Decoupling of Data and Visualization:
- Old: Segmentation rendering was tightly coupled with tool groups.
- New: Segmentation is now treated purely as data, separate from the tools used to interact with it.
- Why: While it's appropriate for tools to be bound to tool groups, viewport-specific functionalities like segmentation rendering should be the responsibility of individual viewports. This separation allows for more flexible rendering and interaction options across different viewports.
-
Polymorphic Segmentation Support:
- The new architecture better supports the concept of polymorphic segmentations, where a single segmentation can have multiple representations (e.g., labelmap, contour, surface) that can be efficiently converted between each other.
- Why: This flexibility allows for more efficient storage, analysis, and real-time visualization of segmentations.
-
Consistent API Across Representation Types:
- The new API provides a unified way to work with different segmentation representations, making it easier to manage complex scenarios involving multiple viewports and representation types.
- Why: This consistency simplifies development and reduces the likelihood of errors when working with different segmentation types.
These architectural changes provide a more robust foundation for working with segmentations, especially in complex multi-viewport scenarios. The new approach has proven to be highly effective and opens up possibilities for future enhancements. While the core concepts remain similar, the way you interact with segmentations in your code will change significantly. This migration guide will walk you through these changes, providing before-and-after examples to help you update your existing codebase to the new architecture.
Segmentation State
The Segmentation
type has been restructured to better organize segment information and representation data. Let's take a look at the changes before we
talk about migration guides.
- Before 📦
- After 🚀🚀
type Segmentation = {
segmentationId: string;
type: Enums.SegmentationRepresentations;
label: string;
activeSegmentIndex: number;
segmentsLocked: Set<number>;
cachedStats: { [key: string]: number };
segmentLabels: { [key: string]: string };
representationData: SegmentationRepresentationData;
};
type Segmentation = {
segmentationId: string;
label: string;
segments: {
[segmentIndex: number]: Segment;
};
representationData: RepresentationsData;
};
type Segment = {
segmentIndex: number;
label: string;
locked: boolean;
cachedStats: { [key: string]: unknown };
active: boolean;
};
The new segmentation state model offers a more organized data structure. Previously scattered information such as cachedStats
, segmentLabels
, and activeSegmentIndex
has been consolidated under the segments
property. This restructuring enhances clarity and efficiency. In the following sections, we'll discuss migration guides that will explain how to access and modify these properties within the new structure. This reorganization primarily affects the segmentation store level.
Representation Data Key
The SegmentationRepresentations
enum has been updated to use title case instead of uppercase to make it match the rest of the Enums.
- Before 📦
- After 🚀🚀
enum SegmentationRepresentations {
Labelmap = 'LABELMAP',
Contour = 'CONTOUR',
Surface = 'SURFACE',
}
enum SegmentationRepresentations {
Labelmap = 'Labelmap',
Contour = 'Contour',
Surface = 'Surface',
}
This change affects how representation data is accessed:
- Before 📦
- After 🚀🚀
const representationData = segmentation.representationData.SURFACE;
const representationData = segmentation.representationData.LABELMAP;
const representationData = segmentation.representationData.CONTOUR;
const representationData = segmentation.representationData.Surface;
const representationData = segmentation.representationData.Labelmap;
const representationData = segmentation.representationData.Contour;
Segmentation Representation
The representation structure has been simplified and is now viewport-specific.
- Before 📦
- After 🚀🚀
type ToolGroupSpecificRepresentation =
| ToolGroupSpecificLabelmapRepresentation
| ToolGroupSpecificContourRepresentation;
type ToolGroupSpecificRepresentationState = {
segmentationRepresentationUID: string;
segmentationId: string;
type: Enums.SegmentationRepresentations;
active: boolean;
segmentsHidden: Set<number>;
colorLUTIndex: number;
};
type SegmentationState = {
toolGroups: {
[key: string]: {
segmentationRepresentations: ToolGroupSpecificRepresentations;
config: SegmentationRepresentationConfig;
};
};
};
type SegmentationRepresentation =
| LabelmapRepresentation
| ContourRepresentation
| SurfaceRepresentation;
type BaseSegmentationRepresentation = {
colorLUTIndex: number;
segmentationId: string;
type: Enums.SegmentationRepresentations;
visible: boolean;
active: boolean;
segments: {
[segmentIndex: number]: {
visible: boolean;
};
};
};
type SegmentationState = {
viewportSegRepresentations: {
[viewportId: string]: Array<SegmentationRepresentation>;
};
};
Previously, the segmentation representation was tool group specific, which led to some issues. In the new structure, segmentation representation is viewport specific. It now consists of a segmentationId, a type, and various settings for that segmentation. As a result of this change, several functions have been removed or modified. Here's a summary of the changes:
Removed Functions
getDefaultSegmentationStateManager
getSegmentationRepresentations
getAllSegmentationRepresentations
getSegmentationIdRepresentations
findSegmentationRepresentationByUID
getToolGroupIdsWithSegmentation
getToolGroupSpecificConfig
setToolGroupSpecificConfig
getGlobalConfig
setGlobalConfig
setSegmentationRepresentationSpecificConfig
getSegmentationRepresentationSpecificConfig
getSegmentSpecificRepresentationConfig
setSegmentSpecificRepresentationConfig
getToolGroupIdFromSegmentationRepresentationUID
addSegmentationRepresentation
getSegmentationRepresentationByUID
New Functions
addSegmentations(segmentationInputArray)
removeSegmentation(segmentationId)
getSegmentation(segmentationId)
getSegmentations()
getSegmentationRepresentation(viewportId, specifier)
getSegmentationRepresentations(viewportId, specifier)
removeSegmentationRepresentation(viewportId, specifier, immediate)
removeAllSegmentationRepresentations()
removeLabelmapRepresentation(viewportId, segmentationId, immediate)
removeContourRepresentation(viewportId, segmentationId, immediate)
removeSurfaceRepresentation(viewportId, segmentationId, immediate)
getViewportSegmentations(viewportId, type)
getViewportIdsWithSegmentation(segmentationId)
getCurrentLabelmapImageIdForViewport(viewportId, segmentationId)
updateLabelmapSegmentationImageReferences(segmentationId, imageIds)
getStackSegmentationImageIdsForViewport(viewportId, segmentationId)
destroy()
Removal of SegmentationDisplayTool
There's no need to add the SegmentationDisplayTool to the toolGroup anymore.
Before
toolGroup2.addTool(SegmentationDisplayTool.toolName);
toolGroup1.setToolEnabled(SegmentationDisplayTool.toolName);
Now
// nothing
Stack Labelmaps
To create a Stack Labelmap, you no longer need to manually create a reference between labelmap imageIds and viewport imageIds. We now handle this process automatically for you.
This is a long Why ...
The previous model required users to provide an imageIdReferenceMap, which linked labelmap imageIds to viewport imageIds. This approach presented several challenges when implementing advanced segmentation use cases:
-
Manual creation of the map was error-prone, particularly regarding the order of imageIds.
-
Once a segmentation was associated with specific viewport imageIds, rendering it elsewhere became problematic. For example:
- Rendering a CT image stack segmentation on a single key image.
- Rendering a CT image stack segmentation on a stack that includes both CT and other images.
- Rendering a DX dual energy segmentation from energy 1 on energy 2.
- Rendering a CT labelmap from a stack viewport on a PT labelmap in the same space.
These scenarios highlight the limitations of the previous model.
We've now transitioned to a system where users only need to provide imageIds. During rendering, we match the viewport's current imageId against the labelmap imageIds and render the segmentation if there's a match. This matching process occurs in the SegmentationStateManager, with the criterion being that the segmentation must be in the same plane as the referenced viewport.
This new approach enables numerous additional use cases and offers greater flexibility in segmentation rendering.
- Before 📦
- After 🚀🚀
segmentation.addSegmentations([
{
segmentationId,
representation: {
type: csToolsEnums.SegmentationRepresentations.Labelmap,
data: {
imageIdReferenceMap:
cornerstoneTools.utilities.segmentation.createImageIdReferenceMap(
imageIds,
segmentationImageIds
),
},
},
},
]);
segmentation.addSegmentations([
{
segmentationId,
representation: {
type: csToolsEnums.SegmentationRepresentations.Labelmap,
data: {
imageIds: segmentationImageIds,
},
},
},
]);
Adding Segmentations
Function Signature Update
The addSegmentations
function now accepts an optional suppressEvents
parameter.
- Before 📦
- After 🚀🚀
function addSegmentations(
segmentationInputArray: SegmentationPublicInput[]
): void;
function addSegmentations(
segmentationInputArray: SegmentationPublicInput[],
suppressEvents?: boolean
): void;
Migration Steps:
- Update any calls to
addSegmentations
to include thesuppressEvents
parameter if needed. - If you don't want to suppress events, you can omit the second parameter.
SegmentationPublicInput Type Updates
The SegmentationPublicInput
type has been extended to include an optional config
property.
- Before 📦
- After 🚀🚀
type SegmentationPublicInput = {
segmentationId: string;
representation: {
type: Enums.SegmentationRepresentations;
data?: RepresentationData;
};
};
type SegmentationPublicInput = {
segmentationId: string;
representation: {
type: Enums.SegmentationRepresentations;
data?: RepresentationData;
};
config?: {
segments?: {
[segmentIndex: number]: Partial<Segment>;
};
label?: string;
};
};
Migration Steps:
- Update any code that creates or manipulates
SegmentationPublicInput
objects to include the newconfig
property if needed. - Replace specific segmentation data types with the generic
RepresentationData
type.
Adding Segmentation Representations
Viewport-Centric Approach
The API now focuses on viewports instead of tool groups, providing more granular control over segmentation representations.
- Before 📦
- After 🚀🚀
function addSegmentationRepresentations(
toolGroupId: string,
representationInputArray: RepresentationPublicInput[],
toolGroupSpecificRepresentationConfig?: SegmentationRepresentationConfig
): Promise<string[]>;
function addSegmentationRepresentations(
viewportId: string,
segmentationInputArray: RepresentationPublicInput[]
);
Migration Steps:
- Replace
toolGroupId
withviewportId
in function calls. - Remove the
toolGroupSpecificRepresentationConfig
parameter. - Update any code that relies on the returned Promise of segmentation representation UIDs.
RepresentationPublicInput Changes
The RepresentationPublicInput
type has been simplified and some properties have been renamed or removed.
- Before 📦
- After 🚀🚀
type RepresentationPublicInput = {
segmentationId: string;
type: Enums.SegmentationRepresentations;
options?: {
segmentationRepresentationUID?: string;
colorLUTOrIndex?: Types.ColorLUT | number;
polySeg?: {
enabled: boolean;
options?: any;
};
};
};
type RepresentationPublicInput = {
segmentationId: string;
type?: Enums.SegmentationRepresentations;
config?: {
colorLUTOrIndex?: Types.ColorLUT[] | number;
};
};
Migration Steps:
- Remove the
options
property and movecolorLUTOrIndex
to theconfig
object. - Remove
segmentationRepresentationUID
andpolySeg
properties if used, polySEG is default enabled. - Update the
colorLUTOrIndex
type to accept an array ofTypes.ColorLUT
instead of a single value.
New Representation-Specific Functions
Version 2 introduces new functions for adding specific types of segmentation representations to viewports.
- Before 📦
- After 🚀🚀
// No equivalent functions in version 1
function addContourRepresentationToViewport(
viewportId: string,
contourInputArray: RepresentationPublicInput[]
);
function addLabelmapRepresentationToViewport(
viewportId: string,
labelmapInputArray: RepresentationPublicInput[]
);
function addSurfaceRepresentationToViewport(
viewportId: string,
surfaceInputArray: RepresentationPublicInput[]
);
Migration Steps:
- Replace generic
addSegmentationRepresentations
calls with the appropriate representation-specific function. - Update the input array to match the new
RepresentationPublicInput
type. - Remove any type-specific logic from your code, as it's now handled by these new functions.
Multi-Viewport Functions
Version 2 introduces new functions for adding segmentation representations to multiple viewports simultaneously.
- Before 📦
- After 🚀🚀
// No equivalent functions in version 1
function addContourRepresentationToViewportMap(viewportInputMap: {
[viewportId: string]: RepresentationPublicInput[];
});
function addLabelmapRepresentationToViewportMap(viewportInputMap: {
[viewportId: string]: RepresentationPublicInput[];
});
function addSurfaceRepresentationToViewportMap(viewportInputMap: {
[viewportId: string]: RepresentationPublicInput[];
});
Migration Steps:
- If you were previously adding representations to multiple tool groups, refactor your code to use these new multi-viewport functions.
- Create a
viewportInputMap
object with viewport IDs as keys and arrays ofRepresentationPublicInput
as values. - Call the appropriate multi-viewport function based on the representation type.
Events
Since we moved from toolGroup to viewport, many events have been renamed to include viewportId
instead of toolGroupId
, and
some event details have been changed to include segmentationId
instead of segmentationRepresentationUID
or toolGroupId
Removal of ToolGroup Specific Events
The triggerSegmentationRepresentationModified
and triggerSegmentationRepresentationRemoved
functions have been removed. Instead, the library now uses a more generalized approach for handling segmentation events.
- Before 📦
- After 🚀🚀
function triggerSegmentationRepresentationModified(
toolGroupId: string,
segmentationRepresentationUID?: string
): void {
// ...
}
function triggerSegmentationRepresentationRemoved(
toolGroupId: string,
segmentationRepresentationUID: string
): void {
// ...
}
function triggerSegmentationRepresentationModified(
viewportId: string,
segmentationId: string,
type?: SegmentationRepresentations
): void {
// ...
}
function triggerSegmentationRepresentationRemoved(
viewportId: string,
segmentationId: string,
type: SegmentationRepresentations
): void {
// ...
}
Migration Steps:
- Replace
toolGroupId
withviewportId
in function calls. - Replace
segmentationRepresentationUID
withsegmentationId
. - Add the
type
parameter to specify the segmentation representation type.
Simplified Segmentation Modified Event
The triggerSegmentationModified
function has been simplified to always require a segmentationId
.
- Before 📦
- After 🚀🚀
function triggerSegmentationModified(segmentationId?: string): void {
// ...
}
function triggerSegmentationModified(segmentationId: string): void {
// ...
}
Migration Steps:
- Ensure that
segmentationId
is always provided when callingtriggerSegmentationModified
. - Remove any logic that handles the case where
segmentationId
is undefined.
Updated Event Detail Types
Several event detail types have been updated to reflect the changes in the segmentation system:
- Before 📦
- After 🚀🚀
type SegmentationRepresentationModifiedEventDetail = {
toolGroupId: string;
segmentationRepresentationUID: string;
};
type SegmentationRepresentationRemovedEventDetail = {
toolGroupId: string;
segmentationRepresentationUID: string;
};
type SegmentationRenderedEventDetail = {
viewportId: string;
toolGroupId: string;
};
type SegmentationRepresentationModifiedEventDetail = {
segmentationId: string;
type: string;
viewportId: string;
};
type SegmentationRepresentationRemovedEventDetail = {
segmentationId: string;
type: string;
viewportId: string;
};
type SegmentationRenderedEventDetail = {
viewportId: string;
segmentationId: string;
type: string;
};
Migration Steps:
- Update event listeners to use the new event detail types.
- Replace
toolGroupId
withviewportId
where applicable. - Use
segmentationId
instead ofsegmentationRepresentationUID
. - Add handling for the new
type
field in event details.
Segmentation Config/Style
In Cornerstone3D version 2.x, we have significantly refactored the segmentation configuration APIs to provide a more flexible and unified approach for managing segmentation styles across different representations (Labelmap, Contour, Surface). The old APIs for getting and setting segmentation configurations have been replaced with new functions that utilize a specifier object to target specific segmentations, viewports, and segments.
Removed Functions
getGlobalConfig
setGlobalConfig
getGlobalRepresentationConfig
setGlobalRepresentationConfig
getToolGroupSpecificConfig
setToolGroupSpecificConfig
getSegmentSpecificConfig
setSegmentSpecificConfig
getSegmentationRepresentationSpecificConfig
setSegmentationRepresentationSpecificConfig
New Functions
getStyle(specifier)
setStyle(specifier, style)
setRenderInactiveSegmentations(viewportId, renderInactiveSegmentations)
getRenderInactiveSegmentations(viewportId)
resetToGlobalStyle()
hasCustomStyle(specifier)
Getting Global Segmentation Config
- Before 📦
- After 🚀
// Get the global segmentation config
const globalConfig = getGlobalConfig();
// Get global representation config for a specific representation type
const labelmapConfig = getGlobalRepresentationConfig(
SegmentationRepresentations.Labelmap
);
// Get the global style for a specific representation type
const labelmapStyle = getStyle({ type: SegmentationRepresentations.Labelmap });
Setting Global Segmentation Config
- Before 📦
- After 🚀
// Set the global segmentation config
setGlobalConfig(newGlobalConfig);
// Set global representation config for a specific representation type
setGlobalRepresentationConfig(
SegmentationRepresentations.Labelmap,
newLabelmapConfig
);
// Set the global style for a specific representation type
setStyle({ type: SegmentationRepresentations.Labelmap }, newLabelmapStyle);
Getting and Setting ToolGroup-Specific Config
ToolGroup-specific configurations have been removed in favor of viewport-specific styles. The following will set the style for a specific viewport and specific segmentation.
- Before 📦
- After 🚀
// Get toolGroup-specific config
const toolGroupConfig = getToolGroupSpecificConfig(toolGroupId);
// Set toolGroup-specific config
setToolGroupSpecificConfig(toolGroupId, newToolGroupConfig);
// Set style for a specific viewport and segmentation representation
setStyle(
{
viewportId: 'viewport1',
segmentationId: 'segmentation1',
type: SegmentationRepresentations.Labelmap,
},
newLabelmapStyle
);
// Get style for a specific viewport and segmentation representation
const style = getStyle({
viewportId: 'viewport1',
segmentationId: 'segmentation1',
type: SegmentationRepresentations.Labelmap,
});
Getting and Setting Segmentation Representation-Specific Config
In Cornerstone3D version 2.x, the functions for getting and setting segmentation representation-specific configurations have been replaced with a unified style management API. The old functions:
getSegmentationRepresentationSpecificConfig
setSegmentationRepresentationSpecificConfig
are no longer available. Instead, you should use the getStyle and setStyle functions with a specifier object to target specific segmentations and representations.
- Before 📦
- After 🚀🚀
// Get segmentation representation-specific config
const representationConfig = getSegmentationRepresentationSpecificConfig(
toolGroupId,
segmentationRepresentationUID
);
// Set segmentation representation-specific config
setSegmentationRepresentationSpecificConfig(
toolGroupId,
segmentationRepresentationUID,
{
LABELMAP: {
renderOutline: true,
outlineWidth: 2,
},
}
);
// Get style for a specific segmentation representation
const style = getStyle({
segmentationId: 'segmentation1',
type: SegmentationRepresentations.Labelmap,
});
// Set style for a specific segmentation representation in all viewports
setStyle(
{
segmentationId: 'segmentation1',
type: SegmentationRepresentations.Labelmap,
},
{
renderOutline: true,
outlineWidth: 2,
}
);
Getting and Setting Segment-Specific Config
- Before 📦
- After 🚀
// Get segment-specific config
const segmentConfig = getSegmentSpecificConfig(
toolGroupId,
segmentationRepresentationUID,
segmentIndex
);
// Set segment-specific config
setSegmentSpecificConfig(
toolGroupId,
segmentationRepresentationUID,
segmentIndex,
newSegmentConfig
);
// Set style for a specific segment
setStyle(
{
segmentationId: 'segmentation1',
type: SegmentationRepresentations.Labelmap,
segmentIndex: 1,
},
newSegmentStyle
);
// Get style for a specific segment
const segmentStyle = getStyle({
segmentationId: 'segmentation1',
type: SegmentationRepresentations.Labelmap,
segmentIndex: 1,
});
Setting Render Inactive Segmentations
The function to enable or disable rendering of inactive segmentations has been updated.
Before
This was part of the segmentation configuration:
setGlobalConfig({ renderInactiveSegmentations: true });
After
Use setRenderInactiveSegmentations
:
// Set whether to render inactive segmentations in a viewport
setRenderInactiveSegmentations(viewportId, true);
// Get whether inactive segmentations are rendered in a viewport
const renderInactive = getRenderInactiveSegmentations(viewportId);
Resetting to Global Style
To reset all segmentation styles to the global style:
resetToGlobalStyle();
Example Migration
- Before 📦
- After 🚀🚀
import {
getGlobalConfig,
getGlobalRepresentationConfig,
getToolGroupSpecificConfig,
setGlobalConfig,
setGlobalRepresentationConfig,
setToolGroupSpecificConfig,
setSegmentSpecificConfig,
getSegmentSpecificConfig,
setSegmentationRepresentationSpecificConfig,
getSegmentationRepresentationSpecificConfig,
} from './segmentationConfig';
// Get the global segmentation config
const globalConfig = getGlobalConfig();
// Set global representation config
setGlobalRepresentationConfig(SegmentationRepresentations.Labelmap, {
renderOutline: true,
outlineWidth: 2,
});
// Set toolGroup-specific config
setToolGroupSpecificConfig(toolGroupId, {
representations: {
LABELMAP: {
renderOutline: false,
},
},
});
// Set segment-specific config
setSegmentSpecificConfig(
toolGroupId,
segmentationRepresentationUID,
segmentIndex,
{
LABELMAP: {
renderFill: false,
},
}
);
import {
getStyle,
setStyle,
setRenderInactiveSegmentations,
getRenderInactiveSegmentations,
resetToGlobalStyle,
hasCustomStyle,
} from '@cornerstonejs/core';
// Get the global style for Labelmap representation
const labelmapStyle = getStyle({ type: SegmentationRepresentations.Labelmap });
// Set the global style for Labelmap representation
setStyle(
{ type: SegmentationRepresentations.Labelmap },
{
renderOutline: true,
outlineWidth: 2,
}
);
// Set style for a specific viewport and segmentation
setStyle(
{
viewportId: 'viewport1',
segmentationId: 'segmentation1',
type: SegmentationRepresentations.Labelmap,
},
{
renderOutline: false,
}
);
// Set style for a specific segment
setStyle(
{
segmentationId: 'segmentation1',
type: SegmentationRepresentations.Labelmap,
segmentIndex: segmentIndex,
},
{
renderFill: false,
}
);
// Set render inactive segmentations for a viewport
setRenderInactiveSegmentations('viewport1', true);
// Get render inactive segmentations setting for a viewport
const renderInactive = getRenderInactiveSegmentations('viewport1');
// Reset all styles to global
resetToGlobalStyle();
Summary
- Unified Style Management: The new
getStyle
andsetStyle
functions provide a unified way to manage segmentation styles across different levels—global, segmentation-specific, viewport-specific, and segment-specific. - Specifier Object: The
specifier
object allows you to target specific viewports, segmentations, and segments.type
is required- if
segmentationId
is provided, the style will be applied to the specific segmentation representation in all viewports - if
segmentationId
andsegmentIndex
are provided, the style will be applied to the specific segment of the specific segmentation representation - if
viewportId
is provided, the style will be applied to all segmentations in the specific viewport - if
viewportId
,segmentationId
, andsegmentIndex
are provided, the style will be applied to the specific segment of the specific segmentation in the specific viewport
- Hierarchy of Styles: The effective style is determined by a hierarchy that considers global styles, segmentation-specific styles, and viewport-specific styles.
Active
Viewport-based Operations
The API now uses viewport IDs instead of tool group IDs for identifying the context of segmentation operations.
- Before 📦
- After 🚀🚀
function getActiveSegmentationRepresentation(toolGroupId: string);
function getActiveSegmentation(toolGroupId: string);
function setActiveSegmentationRepresentation(
toolGroupId: string,
segmentationRepresentationUID: string
);
function getActiveSegmentation(viewportId: string);
function setActiveSegmentation(
viewportId: string,
segmentationId: string,
suppressEvent: boolean = false
);
Migration Steps:
- Replace all instances of
toolGroupId
withviewportId
in function calls. - Update
getActiveSegmentationRepresentation
andgetActiveSegmentation
calls to use the newgetActiveSegmentation
function. - Replace
setActiveSegmentationRepresentation
calls withsetActiveSegmentation
, using the new parameter structure.
Return Type Changes
The return type of getActiveSegmentation
has changed from an implicit undefined
to an explicit Segmentation
type.
- Before 📦
- After 🚀🚀
function getActiveSegmentation(toolGroupId: string);
function getActiveSegmentation(viewportId: string): Segmentation;
Migration Steps:
- Replace all calls to
getActiveSegmentationRepresentation
withgetActiveSegmentation
. - Update any code that relied on the
ToolGroupSpecificRepresentation
type to work with theSegmentation
type instead.
These changes aim to simplify the API and make it more intuitive to use. By focusing on viewport-based operations and removing the distinction between segmentation representations and segmentations, the new API should be easier to work with while maintaining the core functionality of the library.
Visibility
Viewport-Centric Approach
The API now focuses on viewports rather than tool groups, reflecting a shift in the library's architecture.
- Before 📦
- After 🚀🚀
function setSegmentationVisibility(
toolGroupId: string,
segmentationRepresentationUID: string,
visibility: boolean
): void {
// ...
}
function setSegmentationRepresentationVisibility(
viewportId: string,
specifier: {
segmentationId: string;
type?: SegmentationRepresentations;
},
visibility: boolean
): void {
// ...
}
Migration Steps:
- Replace
toolGroupId
withviewportId
in function calls. - Use a
specifier
object instead ofsegmentationRepresentationUID
. - Include
segmentationId
in thespecifier
object. - Optionally specify the
type
of segmentation representation.
Segmentation Representation Types
Version 2 introduces the concept of segmentation representation types, allowing for more granular control over different representation styles.
- Before 📦
- After 🚀🚀
function getSegmentationVisibility(
toolGroupId: string,
segmentationRepresentationUID: string
): boolean | undefined {
// ...
}
function getSegmentationRepresentationVisibility(
viewportId: string,
specifier: {
segmentationId: string;
type: SegmentationRepresentations;
}
): boolean | undefined {
// ...
}
Migration Steps:
- Update function names from
getSegmentationVisibility
togetSegmentationRepresentationVisibility
. - Replace
toolGroupId
withviewportId
. - Use a
specifier
object withsegmentationId
andtype
instead ofsegmentationRepresentationUID
.
Segment-Level Visibility Control
The API for controlling individual segment visibility has been updated to align with the new viewport-centric approach.
- Before 📦
- After 🚀🚀
function setSegmentVisibility(
toolGroupId: string,
segmentationRepresentationUID: string,
segmentIndex: number,
visibility: boolean
): void {
// ...
}
function setSegmentIndexVisibility(
viewportId: string,
specifier: {
segmentationId: string;
type?: SegmentationRepresentations;
},
segmentIndex: number,
visibility: boolean
): void {
// ...
}
Migration Steps:
- Update function names from
setSegmentVisibility
tosetSegmentIndexVisibility
. - Replace
toolGroupId
withviewportId
. - Use a
specifier
object withsegmentationId
and optionaltype
instead ofsegmentationRepresentationUID
.
New Utility Functions
Version 2 introduces new utility functions for managing segmentation visibility.
function getHiddenSegmentIndices(
viewportId: string,
specifier: {
segmentationId: string;
type: SegmentationRepresentations;
}
): Set<number> {
// ...
}
This new function allows you to retrieve a set of hidden segment indices for a specific segmentation representation.
Removed Functions
The following functions have been removed in version 2:
setSegmentsVisibility
getSegmentVisibility
Replace usage of these functions with the new API methods described above.
Why?
Since the visibility should be set on the representation, and segmentation is not the owner of the visibility, a segmentation can have two representations with different visibility on each viewport
Locking
Retrieving Locked Segments
The function to retrieve locked segments has been renamed and its implementation changed:
- Before 📦
- After 🚀🚀
function getLockedSegments(segmentationId: string): number[] | [];
function getLockedSegmentIndices(segmentationId: string): number[] | [];
Migration Steps:
- Update all calls from
getLockedSegments
togetLockedSegmentIndices
. - Be aware that the implementation now uses
Object.keys
andfilter
instead of converting a Set to an array.
Color
Viewport-Centric Approach
The API has shifted from a tool group-based approach to a viewport-centric one. This change affects several function signatures and how segmentations are referenced.
- Before 📦
- After 🚀🚀
function setColorLUT(
toolGroupId: string,
segmentationRepresentationUID: string,
colorLUTIndex: number
): void {
// ...
}
function setColorLUT(
viewportId: string,
segmentationId: string,
colorLUTsIndex: number
): void {
// ...
}
Migration Steps:
- Replace
toolGroupId
withviewportId
in function calls. - Replace
segmentationRepresentationUID
withsegmentationId
. - Update any code that relies on tool group-based segmentation management to use viewport-based management instead.
Color LUT Management
The addColorLUT
function now returns the index of the added color LUT and has an optional colorLUTIndex
parameter.
- Before 📦
- After 🚀🚀
function addColorLUT(colorLUT: Types.ColorLUT, colorLUTIndex: number): void {
// ...
}
function addColorLUT(colorLUT: Types.ColorLUT, colorLUTIndex?: number): number {
// ...
}
Migration Steps:
- Update calls to
addColorLUT
to handle the returned index if needed. - Make the
colorLUTIndex
parameter optional in function calls.
Segment Color Retrieval and Setting
The functions for getting and setting segment colors have been renamed and their signatures updated to align with the new viewport-centric approach.
- Before 📦
- After 🚀🚀
function getColorForSegmentIndex(
toolGroupId: string,
segmentationRepresentationUID: string,
segmentIndex: number
): Types.Color {
// ...
}
function setColorForSegmentIndex(
toolGroupId: string,
segmentationRepresentationUID: string,
segmentIndex: number,
color: Types.Color
): void {
// ...
}
function getSegmentIndexColor(
viewportId: string,
segmentationId: string,
segmentIndex: number
): Types.Color {
// ...
}
function setSegmentIndexColor(
viewportId: string,
segmentationId: string,
segmentIndex: number,
color: Types.Color
): void {
// ...
}
Migration Steps:
- Rename
getColorForSegmentIndex
togetSegmentIndexColor
. - Rename
setColorForSegmentIndex
tosetSegmentIndexColor
. - Update function calls to use
viewportId
instead oftoolGroupId
. - Replace
segmentationRepresentationUID
withsegmentationId
in function calls.
Other Changes
Renaming
getSegmentAtWorldPoint-- > getSegmentIndexAtWorldPoint;
getSegmentAtLabelmapBorder-- > getSegmentIndexAtLabelmapBorder;
getToolGroupIdsWithSegmentation
- Before 📦
- After 🚀🚀
function getToolGroupIdsWithSegmentation(segmentationId: string): string[];
function getViewportIdsWithSegmentation(segmentationId: string): string[];
Migration Steps:
- Replace
getToolGroupIdsWithSegmentation
withgetViewportIdsWithSegmentation
.
Segmentation Representation Management
The way segmentation representations are added, retrieved, and removed has changed significantly.
- Before 📦
- After 🚀🚀
function addSegmentationRepresentation(
toolGroupId: string,
segmentationRepresentation: ToolGroupSpecificRepresentation,
suppressEvents?: boolean
): void;
function getSegmentationRepresentationByUID(
toolGroupId: string,
segmentationRepresentationUID: string
): ToolGroupSpecificRepresentation | undefined;
function removeSegmentationRepresentation(
toolGroupId: string,
segmentationRepresentationUID: string
): void;
function addSegmentationRepresentation(
viewportId: string,
segmentationRepresentation: SegmentationRepresentation,
suppressEvents?: boolean
): void;
function getSegmentationRepresentation(
viewportId: string,
specifier: {
segmentationId: string;
type: SegmentationRepresentations;
}
): SegmentationRepresentation | undefined;
function removeSegmentationRepresentation(
viewportId: string,
specifier: {
segmentationId: string;
type: SegmentationRepresentations;
},
immediate?: boolean
): void;
Migration Steps:
- Update all calls to
addSegmentationRepresentation
to useviewportId
instead oftoolGroupId
. - Replace
getSegmentationRepresentationByUID
withgetSegmentationRepresentation
, using the new specifier object. - Update
removeSegmentationRepresentation
calls to use the new specifier object instead ofsegmentationRepresentationUID
.
PolySEG
Import
The PolySEG has been unbundled and placed in a separate external package. To use it, add the peerImport
function to your init
function for Cornerstone Core.
async function peerImport(moduleId) {
if (moduleId === '@icr/polyseg-wasm') {
return import('@icr/polyseg-wasm');
}
}
import { init } from '@cornerstonejs/core';
await init({ peerImport });
Options
You don't need to provide polyseg options for the segmentation representation. It will automatically use PolySeg if the specified representation is unavailable.
- Before 📦
- After 🚀🚀
await segmentation.addSegmentationRepresentations(toolGroupId2, [
{
segmentationId,
type: csToolsEnums.SegmentationRepresentations.Labelmap,
options: {
polySeg: {
enabled: true,
},
},
},
]);
await segmentation.addSegmentationRepresentations(viewportId2, [
{
segmentationId,
type: csToolsEnums.SegmentationRepresentations.Labelmap,
},
]);
Actor UID for labelmaps
The way the actorUID is generated has changed to use a combination of segmentationId and SegmentationRepresentations.Labelmap.
- Before 📦
- After 🚀
const volumeInputs: Types.IVolumeInput[] = [
{
volumeId: labelMapData.volumeId,
actorUID: segmentationRepresentationUID,
visibility,
blendMode: Enums.BlendModes.MAXIMUM_INTENSITY_BLEND,
},
];
const volumeInputs: Types.IVolumeInput[] = [
{
volumeId,
actorUID: `${segmentationId}-${SegmentationRepresentations.Labelmap}`,
visibility,
blendMode: Enums.BlendModes.MAXIMUM_INTENSITY_BLEND,
},
];
We've updated the actorUID
to ${segmentationId}-${SegmentationRepresentations.Labelmap}
. This change allows us to uniquely identify representations without relying on the segmentationRepresentationUID
.
For this mean, getSegmentationActor
is added for you to get the actor for a given labelmap
export function getSegmentationActor(
viewportId: string,
specifier: {
segmentationId: string;
type: SegmentationRepresentations;
}
): Types.VolumeActor | Types.ImageActor | undefined;
New Utilities
clearSegmentValue
is added to clear a specific segment value in a segmentation,
it will make the segment value to 0
function clearSegmentValue(
segmentationId: string,
segmentIndex: number
)
Renaming and Nomenclature
Types
PointsManager is now IPointsManager
migration
import { IPointsManager } from '@cornerstonejs/tools/types';
Units
getCalibratedLengthUnitsAndScale Signature
It is highly unlikely that you were using this function directly, but if you were, here's the migration
The return type of the function has changed slightly, with units
and areaUnits
renamed to unit
and areaUnit
respectively.
- Before 📦
- After 🚀
const getCalibratedLengthUnitsAndScale = (image, handles) => {
// ...
return { units, areaUnits, scale };
};
const getCalibratedLengthUnitsAndScale = (image, handles) => {
// ...
return { unit, areaUnit, scale };
};
getModalityUnit -> getPixelValueUnits
To make more sense
Details
Why?
There was too much inconsistency in the units used throughout the library. We hadunit
, areaUnits
, modalityUnit
, and various others. Now, we have consolidated these units. You need to update your codebase to reflect the new unit system if you are hydrating annotations for Cornerstone3D.In addition modalityUnit is now pixelValueUnits to reflect the correct term, since for a single modality there can be multiple pixel values (e.g, PT SUV, PT RAW, PT PROC)
BasicStatsCalculator
the option noPointsCollection
has been renamed to storePointData
getSegmentAtWorldPoint -> getSegmentIndexAtWorldPoint
getSegmentAtLabelmapBorder -> getSegmentIndexAtLabelmapBorder
Others
roundNumber
The utility has been relocated from @cornerstonejs/tools
utilities to @cornerstonejs/core/utilities
.
migration
import { roundNumber } from '@cornerstonejs/core/utilities';
jumpToSlice
The utility has been relocated from @cornerstonejs/tools
utilities to @cornerstonejs/core/utilities
.
migration
import { jumpToSlice } from '@cornerstonejs/core/utilities';
pointInShapeCallback
1. New Import Path
The pointInShapeCallback
function has been moved. Update your imports as follows:
import { pointInShapeCallback } from '@cornerstonejs/core/utilities';
2. Updated Usage
The function signature has changed to use an options object for improved clarity and flexibility. Below is a guide to how the usage has changed.
Old Usage:
const pointsInShape = pointInShapeCallback(
imageData,
shapeFnCriteria,
(point) => {
// callback logic for each point
},
boundsIJK
);
New Usage:
const pointsInShape = pointInShapeCallback(imageData, {
pointInShapeFn: shapeFnCriteria,
callback: (point) => {
// callback logic for each point
},
boundsIJK: boundsIJK,
returnPoints: true, // Optionally, to return the points inside the shape
});
Key Changes:
- Options Object: Configuration parameters such as
pointInShapeFn
,callback
,boundsIJK
, andreturnPoints
are now passed through an options object. - Return Points: Use the
returnPoints
option to specify if you want to return the points within the shape, previously it was always returning the points. If you relied on returning points directly, make sure to includestorePointData: true
in the tool options when you active it