docs: update to next version [BUMP BETA] (#4493)

This commit is contained in:
Alireza authored and GitHub committed 2024-11-12 16:18:33 -05:00
1 parent f4775eccae
commit 6d0fa11ff8
299 files changed
+5417 -1311

No files matched your search

@@ -0,0 +1,48 @@
---
id: seg-new-arch
title: New Architecture
---
## New Architecture
* **Viewport-Centric Architecture**
* Previous: Segmentations were tied to toolGroups
* Now: Segmentations are tied directly to viewports
* Impact: More granular control but requires significant code changes
* **Representation Management**
* Previous: Required managing segmentation representation UIDs
* Now: Uses simpler segmentationId + type combination
* Impact: Simplified but requires API updates
If you are not familiar with the difference between a segmentation and a segmentation representation, below
<details>
<summary>Read More</summary>
In Cornerstone3DTools, we have decoupled the concept of a Segmentation from a Segmentation Representation. This means that from one Segmentation we can create multiple Segmentation Representations. For instance, a Segmentation Representation of a 3D Labelmap, can be created from a Segmentation data, and a Segmentation Representation of a Contour can be created from the same Segmentation data. This way we have decouple the presentational aspect of a Segmentation from the underlying data.
Similar relationship structure has been adapted in popular medical imaging softwares such as 3D Slicer with the addition of polymorph segmentation.
- https://github.com/PerkLab/PolySeg
- https://www.slicer.org/
</details>
### Architecture Overview
The new architecture in Cornerstone3D 2.0 makes a clear distinction between:
* A segmentation (the data structure containing segments)
* A segmentation representation (how that segmentation is visualized in a specific viewport)
Let's now review what has changed
@@ -0,0 +1,433 @@
---
id: seg-api
title: SegmentationService API
---
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:
```js
/**
* 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;
};
```
<details>
<summary>Compared to Cornerstone3D 1.x</summary>
Previously this function was returning this
```js
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.
</details>
---
## 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)
```js
// Returns full segmentation object
public getActiveSegmentation(): Segmentation {
const segmentations = this.getSegmentations();
return segmentations.find(segmentation => segmentation.isActive);
}
```
After (3.9)
```js
public getActiveSegmentation(viewportId: string): Segmentation | null {
return cstSegmentation.activeSegmentation.getActiveSegmentation(viewportId);
}
```
<details>
<summary>Key Changes</summary>
1. **Viewport Specificity**
- Before: Global active segmentation across all tool groups
- After: Active segmentation per viewport
2. **Required Parameters**
- Before: No parameters needed
- After: Requires viewportId parameter
</details>
<details>
<summary>Migration Examples</summary>
**Before:**
```js
// Get active segmentation
const activeSegmentation = segmentationService.getActiveSegmentation();
if (activeSegmentation) {
console.log('Active segmentation:', activeSegmentation.segmentationId);
console.log('Active segment:', activeSegmentation.activeSegmentIndex);
}
```
**After:**
```js
// Get active segmentation for specific viewport
const activeSegmentation = segmentationService.getActiveSegmentation('viewport1');
```
</details>
---
## getToolGroupIdsWithSegmentation
is now -> `getViewportIdsWithSegmentation` as you guessed
## setActiveSegmentationForToolGroup
-> setActiveSegmentation
**Before (OHIF 3.8)**
```js
setActiveSegmentationForToolGroup(
segmentationId: string,
toolGroupId?: string,
suppressEvents?: boolean
): void
```
**After (OHIF 3.9)**
```js
setActiveSegmentation(
viewportId: string,
segmentationId: string
): void
```
<details>
<summary>Migration Examples</summary>
1. **Basic Usage Update**
```js
// Before - OHIF 3.8
segmentationService.setActiveSegmentationForToolGroup(
segmentationId,
toolGroupId
);
// After - OHIF 3.9
segmentationService.setActiveSegmentation(
viewportId,
segmentationId
);
```
</details>
---
## 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)**
```js
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)**
```js
addSegment(
segmentationId: string,
config: {
segmentIndex?: number;
label?: string;
isLocked?: boolean;
active?: boolean;
color?: csTypes.Color;
visibility?: boolean;
}
): void
```
<details>
<summary>Key Changes</summary>
1. **Configuration Structure**
- Removed double nested `properties` object
- Configuration options now at top level
- Removed `toolGroupId` parameter
- Removed `opacity` parameter (now part of color)
2. **Segment Index Generation**
- Changed from length-based to max-value-based indexing
- More reliable for non-sequential segment indices
3. **Color Handling**
- Color now includes alpha channel (opacity)
- Applied to all relevant viewports automatically
</details>
<details>
<summary>Migration Examples</summary>
1. **Basic Segment Creation**
```js
// Before - OHIF 3.8
segmentationService.addSegment(segmentationId, {
properties: {
label: 'Segment 1'
}
});
// After - OHIF 3.9
segmentationService.addSegment(segmentationId, {
label: 'Segment 1'
});
```
2. **Creating Segment with Color**
```js
// 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
});
```
3. **Setting Visibility and Lock Status**
```js
// 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
});
```
4. **Complete Configuration Example**
```js
// 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
});
```
</details>
<details>
<summary>Important Changes</summary>
1. **Tool Group Removal**
```js
// 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
});
```
2. **Segment Index Generation**
```js
// 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;
```
3. **Color and Opacity**
```js
// 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
});
```
</details>
---
---
## getActiveSegment
now requires viewportId, since we have moved away from global active segmentation to viewport specific one
**API Changes**
```js
// Before
getActiveSegment(): Segment
// After
getActiveSegment(viewportId: string): Segment | null
```
@@ -0,0 +1,189 @@
---
id: seg-representation
title: Segmentation Representations
---
## Segmentation Representation Management API
```js
addSegmentationRepresentationToToolGroup
removeSegmentationRepresentationFromToolGroup
getSegmentationRepresentationsForToolGroup
```
In Cornerstone3D 2.0, segmentation representation management has shifted from a tool group-centric approach to a viewport-centric approach. This architectural change provides better control over segmentation rendering and simplifies the mental model for managing segmentations.
### Adding Segmentation Representations
**Before (3.8)**:
```js
// Tool group-based approach
await segmentation.addSegmentationRepresentationToToolGroup(
toolGroupId,
segmentationId,
hydrateSegmentation,
csToolsEnums.SegmentationRepresentations.Labelmap
);
```
**After (3.9)**:
```js
// Viewport-centric approach
await segmentation.addSegmentationRepresentation(
viewportId,
{
segmentationId: segmentationId,
type: csToolsEnums.SegmentationRepresentations.Labelmap,
}
);
```
### Removing Segmentation Representations
**Before** :
```js
// Remove specific representations from a tool group
segmentation.removeSegmentationRepresentationFromToolGroup(
toolGroupId,
[segmentationRepresentationUID]
);
// Remove all representations from a tool group
segmentation.removeSegmentationRepresentationFromToolGroup(toolGroupId);
```
**After**
```js
// Remove specific representation from a viewport
segmentation.removeSegmentationRepresentation(
viewportId,
{
segmentationId: segmentationId,
type: csToolsEnums.SegmentationRepresentations.Labelmap
}
);
// Remove all representations from a viewport
segmentation.removeSegmentationRepresentations(viewportId);
```
### Getting Segmentation Representations
**Before**:
```js
// Get representations for a tool group
const representations = segmentation.getSegmentationRepresentationsForToolGroup(toolGroupId);
```
**After** :
```js
// Get all representations for a viewport
const representations = segmentation.getSegmentationRepresentations(viewportId);
// Get specific type of representations
const labelmapReps = segmentation.getSegmentationRepresentations(viewportId, {
type: csToolsEnums.SegmentationRepresentations.Labelmap
});
// Get representations for specific segmentation
const segmentationReps = segmentation.getSegmentationRepresentations(viewportId, {
segmentationId: segmentationId
});
// Get specific representation
const representation = segmentation.getSegmentationRepresentation(viewportId, {
segmentationId: segmentationId,
type: csToolsEnums.SegmentationRepresentations.Labelmap
});
```
### Understanding the Specifier Pattern
The Cornerstone3D 2.0 (OHIF 3.9) API introduces a "specifier" pattern that provides more flexible and precise control over segmentation representations. A specifier is an object that can include:
```js
type Specifier = {
segmentationId?: string; // The ID of the segmentation
type?: SegmentationRepresentations; // The type of representation (Labelmap, Contour, etc.)
}
```
The specifier pattern allows for:
1. **Precise Targeting**: You can target specific segmentations and representation types
- Allows direct access to individual segmentations
- Enables filtering by representation type
2. **Flexible Querying**: You can get all representations of a certain type or for a specific segmentation
- Query by segmentation ID
- Query by representation type
- Combine queries for specific needs
3. **Granular Control**: You can manage representations at different levels of specificity
- Viewport level control
- Segmentation level control
- Individual representation type control
### Examples of Specifier Usage
```js
// Get all labelmap representations in a viewport
const labelmaps = segmentation.getSegmentationRepresentations(viewportId, {
type: csToolsEnums.SegmentationRepresentations.Labelmap
});
// Get all representations of a specific segmentation (including contour, labelmap, surface)
const segReps = segmentation.getSegmentationRepresentations(viewportId, {
segmentationId: 'seg123'
});
// Get a specific representation
const specificRep = segmentation.getSegmentationRepresentation(viewportId, {
segmentationId: 'seg123',
type: csToolsEnums.SegmentationRepresentations.Labelmap
});
```
<details>
<summary>Benefits of the New Approach</summary>
1. **Direct Viewport Control**:
- Each viewport can have its own unique representation configuration
- No need to create separate tool groups for different viewport representations
2. **Simpler Mental Model**:
- Representations are directly tied to where they're displayed
- No intermediate tool group layer to manage
3. **More Flexible Rendering**:
- Each viewport can render the same segmentation differently
- Better support for multiple views of the same data
4. **Improved Type Safety**:
- Specifier pattern provides better TypeScript support
- More explicit API with clearer intentions
</details>
<details>
<summary>Migration Tips</summary>
1. **Replace Tool Group References**:
- Search your codebase for `toolGroupId` references in segmentation code
- Replace with appropriate `viewportId` references
2. **Update Event Handlers**:
- Update any code listening for segmentation events
- Events now include viewportId instead of toolGroupId
3. **Review Representation Management**:
- Identify where you manage segmentation representations
- Convert to using the new viewport-centric methods
4. **Consider Viewport Context**:
- Think about segmentation representation in terms of viewport display
- Use specifiers to target specific representations when needed
</details>
@@ -0,0 +1,215 @@
---
id: seg-creation
title: Segmentation Creation
---
## createEmptySegmentationForViewport
is now `createLabelmapForViewport` to align with other segmentation creation methods.
Run it using `commandsManager.runCommand('createLabelmapForViewport', {viewportId})`.
## createSegmentationForDisplaySet
is now -> `createLabelmapForDisplaySet`
Since we are moving towards segmentations be contours as well, this is renamed to clearly state the purpose.
Since OHIF 3.9 introduced Stack Segmentation support, we no longer generate a volume-based labelmap or convert the viewport to a volume viewport by default. Our default creation is now stack-based.
API Changes
- `createSegmentationForDisplaySet` has been renamed to `createLabelmapForDisplaySet`.
- Pass a `displaySet` object instead of a `displaySetInstanceUID`. This change enhances type safety and flexibility, accommodating future updates to the `displaySetService`.
**Before (OHIF 3.8)**
```js
async createSegmentationForDisplaySet(
displaySetInstanceUID: string,
options?: {
segmentationId: string;
FrameOfReferenceUID: string;
label: string;
}
): Promise<string>
```
**After (OHIF 3.9)**
```js
// Method 1: Display Set Based
async createLabelmapForDisplaySet(
displaySet: DisplaySet,
options?: {
segmentationId?: string;
label: string;
segments?: {
[segmentIndex: number]: Partial<Segment>
};
}
): Promise<string>
```
<details>
<summary>Migration Examples</summary>
```js
// Before - OHIF 3.8
const segmentationId = await segmentationService.createSegmentationForDisplaySet(
displaySetInstanceUID,
{
label: 'My Segmentation'
}
);
```
```js
// After - OHIF 3.9
// Option 1: If you have a display set UID
const displaySet = displaySetService.getDisplaySetByUID(displaySetInstanceUID);
const segmentationId = await segmentationService.createLabelmapForDisplaySet(
displaySet,
{
label: 'My Segmentation'
}
);
```
</details>
---
## createSegmentationForRTDisplaySet
**Before (OHIF 3.8)**
```js
async createSegmentationForRTDisplaySet(
rtDisplaySet,
segmentationId?: string,
suppressEvents = false
): Promise<string>
```
**After (OHIF 3.9)**
```js
async createSegmentationForRTDisplaySet(
rtDisplaySet,
options: {
segmentationId?: string;
type: SegmentationRepresentations; // not required, defaults to Contour
}
): Promise<string>
```
<details>
<summary>Migration Examples</summary>
if you were not passing segmentationId, you don't need to change anything
```js
// Before - OHIF 3.8
const segmentationId = await segmentationService.createSegmentationForRTDisplaySet(
rtDisplaySet
);
// After - OHIF 3.9
const segmentationId = await segmentationService.createSegmentationForRTDisplaySet(
rtDisplaySet,
);
```
if you were passing segmentationId, you need to update the API to pass an options object and set the segmentationId in there.
```js
// Before - OHIF 3.8
const segmentationId = await segmentationService.createSegmentationForRTDisplaySet(
rtDisplaySet,
'custom-id',
);
// After - OHIF 3.9
const segmentationId = await segmentationService.createSegmentationForRTDisplaySet(
rtDisplaySet,
{
segmentationId: 'custom-id',
type: csToolsEnums.SegmentationRepresentations.Contour
}
);
```
</details>
---
## createSegmentationForSEGDisplaySet Changes
**Before (OHIF 3.8)**
```js
async createSegmentationForSEGDisplaySet(
segDisplaySet,
segmentationId?: string,
suppressEvents = false
): Promise<string>
```
**After (OHIF 3.9)**
```js
async createSegmentationForSEGDisplaySet(
segDisplaySet,
options: {
segmentationId?: string;
type: SegmentationRepresentations; // not required, defaults to Labelmap
}
): Promise<string>
```
<details>
<summary>Migration Examples</summary>
1. **Basic Usage Update**
```
// Before - OHIF 3.8
const segmentationId = await segmentationService.createSegmentationForSEGDisplaySet(
segDisplaySet
);
// After - OHIF 3.9
const segmentationId = await segmentationService.createSegmentationForSEGDisplaySet(
segDisplaySet,
{
type: csToolsEnums.SegmentationRepresentations.Labelmap
}
);
```
2. **Custom Configuration**
```
// Before - OHIF 3.8
const segmentationId = await segmentationService.createSegmentationForSEGDisplaySet(
segDisplaySet,
'custom-id',
false
);
// After - OHIF 3.9
const segmentationId = await segmentationService.createSegmentationForSEGDisplaySet(
segDisplaySet,
{
segmentationId: 'custom-id',
type: csToolsEnums.SegmentationRepresentations.Labelmap
}
);
```
</details>
---
@@ -0,0 +1,193 @@
---
id: seg-service-mod
title: SegmentationService Modifications
---
---
## Segmentation Representation Management API
```js
addSegmentationRepresentationToToolGroup
removeSegmentationRepresentationFromToolGroup
getSegmentationRepresentationsForToolGroup
```
In Cornerstone3D 2.0, segmentation representation management has shifted from a tool group-centric approach to a viewport-centric approach. This architectural change provides better control over segmentation rendering and simplifies the mental model for managing segmentations.
### Adding Segmentation Representations
**Before (3.8)**:
```js
// Tool group-based approach
await segmentation.addSegmentationRepresentationToToolGroup(
toolGroupId,
segmentationId,
hydrateSegmentation,
csToolsEnums.SegmentationRepresentations.Labelmap
);
```
**After (3.9)**:
```js
// Viewport-centric approach
await segmentation.addSegmentationRepresentation(
viewportId,
{
segmentationId: segmentationId,
type: csToolsEnums.SegmentationRepresentations.Labelmap,
}
);
```
### Removing Segmentation Representations
**Before** :
```js
// Remove specific representations from a tool group
segmentation.removeSegmentationRepresentationFromToolGroup(
toolGroupId,
[segmentationRepresentationUID]
);
// Remove all representations from a tool group
segmentation.removeSegmentationRepresentationFromToolGroup(toolGroupId);
```
**After**
```js
// Remove specific representation from a viewport
segmentation.removeSegmentationRepresentation(
viewportId,
{
segmentationId: segmentationId,
type: csToolsEnums.SegmentationRepresentations.Labelmap
}
);
// Remove all representations from a viewport
segmentation.removeSegmentationRepresentations(viewportId);
```
### Getting Segmentation Representations
**Before**:
```js
// Get representations for a tool group
const representations = segmentation.getSegmentationRepresentationsForToolGroup(toolGroupId);
```
**After** :
```js
// Get all representations for a viewport
const representations = segmentation.getSegmentationRepresentations(viewportId);
// Get specific type of representations
const labelmapReps = segmentation.getSegmentationRepresentations(viewportId, {
type: csToolsEnums.SegmentationRepresentations.Labelmap
});
// Get representations for specific segmentation
const segmentationReps = segmentation.getSegmentationRepresentations(viewportId, {
segmentationId: segmentationId
});
// Get specific representation
const representation = segmentation.getSegmentationRepresentation(viewportId, {
segmentationId: segmentationId,
type: csToolsEnums.SegmentationRepresentations.Labelmap
});
```
### Understanding the Specifier Pattern
The Cornerstone3D 2.0 (OHIF 3.9) API introduces a "specifier" pattern that provides more flexible and precise control over segmentation representations. A specifier is an object that can include:
```js
type Specifier = {
segmentationId?: string; // The ID of the segmentation
type?: SegmentationRepresentations; // The type of representation (Labelmap, Contour, etc.)
}
```
The specifier pattern allows for:
1. **Precise Targeting**: You can target specific segmentations and representation types
- Allows direct access to individual segmentations
- Enables filtering by representation type
2. **Flexible Querying**: You can get all representations of a certain type or for a specific segmentation
- Query by segmentation ID
- Query by representation type
- Combine queries for specific needs
3. **Granular Control**: You can manage representations at different levels of specificity
- Viewport level control
- Segmentation level control
- Individual representation type control
### Examples of Specifier Usage
```js
// Get all labelmap representations in a viewport
const labelmaps = segmentation.getSegmentationRepresentations(viewportId, {
type: csToolsEnums.SegmentationRepresentations.Labelmap
});
// Get all representations of a specific segmentation (including contour, labelmap, surface)
const segReps = segmentation.getSegmentationRepresentations(viewportId, {
segmentationId: 'seg123'
});
// Get a specific representation
const specificRep = segmentation.getSegmentationRepresentation(viewportId, {
segmentationId: 'seg123',
type: csToolsEnums.SegmentationRepresentations.Labelmap
});
```
<details>
<summary>Benefits of the New Approach</summary>
1. **Direct Viewport Control**:
- Each viewport can have its own unique representation configuration
- No need to create separate tool groups for different viewport representations
2. **Simpler Mental Model**:
- Representations are directly tied to where they're displayed
- No intermediate tool group layer to manage
3. **More Flexible Rendering**:
- Each viewport can render the same segmentation differently
- Better support for multiple views of the same data
4. **Improved Type Safety**:
- Specifier pattern provides better TypeScript support
- More explicit API with clearer intentions
</details>
<details>
<summary>Migration Tips</summary>
1. **Replace Tool Group References**:
- Search your codebase for `toolGroupId` references in segmentation code
- Replace with appropriate `viewportId` references
2. **Update Event Handlers**:
- Update any code listening for segmentation events
- Events now include viewportId instead of toolGroupId
3. **Review Representation Management**:
- Identify where you manage segmentation representations
- Convert to using the new viewport-centric methods
4. **Consider Viewport Context**:
- Think about segmentation representation in terms of viewport display
- Use specifiers to target specific representations when needed
</details>
---
@@ -0,0 +1,362 @@
---
id: seg-style
title: SegmentationService Style
---
## Style
### setSegmentVisibility
since visibility is viewport concern and representation is what is being toggled ->
**Before (OHIF 3.8)**
```js
setSegmentVisibility(
segmentationId: string,
segmentIndex: number,
isVisible: boolean,
toolGroupId?: string
): void
```
**After (OHIF 3.9)**
```js
setSegmentVisibility(
viewportId: string,
segmentationId: string,
segmentIndex: number,
isVisible: boolean,
type?: SegmentationRepresentations
): void
```
<details>
<summary>Migration Example</summary>
```js
// Before
segmentationService.setSegmentVisibility(
'segmentation1',
1,
true,
'toolGroup1'
);
// After
segmentationService.setSegmentVisibility(
'viewport1',
'segmentation1',
1,
true
);
```
**Getting Viewport IDs**
When you need to update visibility across multiple viewports:
```js
// Before
const toolGroupIds = ['toolGroup1', 'toolGroup2'];
toolGroupIds.forEach(toolGroupId => {
segmentationService.setSegmentVisibility(
'segmentation1',
1,
true,
toolGroupId
);
});
// After
const viewportIds = segmentationService.getViewportIdsWithSegmentation('segmentation1');
viewportIds.forEach(viewportId => {
segmentationService.setSegmentVisibility(
viewportId,
'segmentation1',
1,
true
);
});
```
</details>
### get/set Configuration -> get/setStyle
The segmentation configuration system has been completely redesigned:
- Moved from global/toolGroup configuration to viewport-specific styles
- Split rendering of inactive segmentations into separate API
- More granular control over styles at different levels (global, segmentation, viewport, segment)
**Before (OHIF 3.8)**
```js
interface SegmentationConfig {
brushSize: number;
brushThresholdGate: number;
fillAlpha: number;
fillAlphaInactive: number;
outlineWidthActive: number;
renderFill: boolean;
renderInactiveSegmentations: boolean;
renderOutline: boolean;
outlineOpacity: number;
outlineOpacityInactive: number;
}
```
**After (OHIF 3.9)**
```js
// Style Types
interface StyleSpecifier {
viewportId?: string;
segmentationId?: string;
type: SegmentationRepresentations;
segmentIndex?: number;
}
interface LabelmapStyle {
renderOutline: boolean;
outlineWidth: number;
renderFill: boolean;
fillAlpha: number;
outlineAlpha: number;
// ....
}
// Functions
getStyle(specifier: StyleSpecifier): LabelmapStyle | ContourStyle | SurfaceStyle;
setStyle(specifier: StyleSpecifier, style: LabelmapStyle | ContourStyle | SurfaceStyle): void;
setRenderInactiveSegmentations(viewportId: string, renderInactive: boolean): void;
getRenderInactiveSegmentations(viewportId: string): boolean;
```
**Before:**
```js
// Get global configuration
const config = segmentationService.getConfiguration();
console.log(config.fillAlpha, config.renderOutline);
// Get tool group specific config
const toolGroupConfig = segmentationService.getConfiguration('toolGroup1');
```
**After:**
```js
// Get global style for labelmap
const labelmapStyle = segmentationService.getStyle({
type: SegmentationRepresentations.Labelmap
});
// Get viewport-specific style
const viewportStyle = segmentationService.getStyle({
viewportId: 'viewport1',
type: SegmentationRepresentations.Labelmap
});
// Get segmentation-specific style
const segmentationStyle = segmentationService.getStyle({
segmentationId: 'seg1',
type: SegmentationRepresentations.Labelmap
});
// Get segment-specific style
const segmentStyle = segmentationService.getStyle({
segmentationId: 'seg1',
type: SegmentationRepresentations.Labelmap,
segmentIndex: 1
});
```
**Setting Configuration/Style**
**Before:**
```js
segmentationService.setConfiguration({
fillAlpha: 0.5,
outlineWidthActive: 2,
renderOutline: true,
renderFill: true,
renderInactiveSegmentations: true
});
```
**After:**
```js
// Set global style
segmentationService.setStyle(
{ type: SegmentationRepresentations.Labelmap },
{
fillAlpha: 0.5,
outlineWidth: 2,
renderOutline: true,
renderFill: true
}
);
// Set viewport-specific style
segmentationService.setStyle(
{
viewportId: 'viewport1',
type: SegmentationRepresentations.Labelmap
},
{
fillAlpha: 0.5,
outlineWidth: 2
}
);
// Handle inactive segmentations separately
segmentationService.setRenderInactiveSegmentations('viewport1', true);
```
<details>
<summary>Migration Examples</summary>
**Combining Multiple Style Settings**
**Before:**
```js
segmentationService.setConfiguration({
fillAlpha: 0.5,
fillAlphaInactive: 0.2,
outlineWidthActive: 2,
outlineOpacity: 1,
outlineOpacityInactive: 0.5,
renderOutline: true,
renderFill: true,
renderInactiveSegmentations: true
});
```
**After:**
```js
// Set base style
segmentationService.setStyle(
{ type: SegmentationRepresentations.Labelmap },
{
fillAlpha: 0.5,
outlineWidth: 2,
outlineAlpha: 1,
renderOutline: true,
renderFill: true
}
);
```
</details>
**Set inactive rendering per viewport**
```js
segmentationService.setRenderInactiveSegmentations('viewport1', true);
// Set style for inactive segments if needed
segmentationService.setStyle(
{
viewportId: 'viewport1',
type: SegmentationRepresentations.Labelmap,
segmentationId: 'seg1'
},
{
fillAlpha: 0.2,
outlineAlpha: 0.5
}
);
```
---
## setSegmentRGBAColor , setSegmentOpacity, setSegmentRGBA
Previously, the SegmentationService had multiple redundant methods for setting colors and opacity (`setSegmentRGBA`, `setSegmentColor`, `setSegmentOpacity`). This led to confusion and potential state inconsistencies between the service and Cornerstone.js Tools.
The old methods (`setSegmentRGBA`, `setSegmentRGBA`, and `setSegmentOpacity`) are now removed.
1. Replace `setSegmentRGBAColor`, `setSegmentRGBA`, and `setSegmentOpacity` calls: Replace all instances of the old methods with the new `setSegmentColor` method. Note that you now need to provide the `viewportId` as the first argument since segment color is managed per viewport and representation in cornerstone3D.
**Before**
```js
// Old API:
segmentationService.setSegmentRGBAColor(segmentationId, segmentIndex, rgbaColor, toolGroupId);
segmentationService.setSegmentRGBA(segmentationId, segmentIndex, rgbaColor, toolGroupId);
segmentationService.setSegmentOpacity(segmentationId, segmentIndex, opacity, toolGroupId);
```
**After**
```js
// New API:
segmentationService.setSegmentColor(viewportId, segmentationId, segmentIndex, color); // color is an array of [red, green, blue, alpha]
```
The new `color` argument is an array representing the RGBA color, where the alpha component determines the opacity. Since the Cornerstone Tools library handles segment color per viewport and representation, we require the `viewportId` as an argument now.
2. **Retrieve Segment Color using** `getSegmentColor`: The new `getSegmentColor` provides a way to fetch the color of a segment within a specific viewport.
```js
const color = segmentationService.getSegmentColor(viewportId, segmentationId, segmentIndex); //returns [r, g, b, a]
```
---
## ToggleSegmentationVisibility
In Cornerstone3D v2.x, `toggleSegmentationVisibility` has been replaced with `toggleSegmentationRepresentationVisibility`. This change reflects the fact that
a representation is what is being toggled, not the segmentation.
**Before (OHIF 3.8)**
```js
// Toggle visibility for a segmentation globally
segmentationService.toggleSegmentationVisibility(segmentationId);
```
**After (OHIF 3.9)**
```js
// Toggle visibility for a segmentation representation in a specific viewport
segmentationService.toggleSegmentationRepresentationVisibility(viewportId, {
segmentationId: segmentationId,
type: csToolsEnums.SegmentationRepresentations.Labelmap
});
```
**Migration Steps**
1. Update all calls to `toggleSegmentationVisibility` to use `toggleSegmentationRepresentationVisibility`
2. Add the required `viewportId` parameter
3. Add a `type` parameter specifying the representation type (e.g., Labelmap, Contour)
4. If you were toggling visibility across all viewports, you'll need to loop through the viewports:
<details>
<summary>Additional Notes</summary>
- Each viewport can now have independent visibility settings for the same segmentation
- The visibility state is specific to the representation type (Labelmap, Contour, etc.)
- To check current visibility, use `getSegmentationRepresentationVisibility(viewportId, { segmentationId, type })`
</details>
---
@@ -0,0 +1,374 @@
---
id: seg-other
title: Other Changes
---
## addOrUpdateSegmentation
This was a public method but there is a good chance you were not using it
**Before (OHIF 3.8)**
```js
// Before
addOrUpdateSegmentation(
segmentation: Segmentation,
suppressEvents = false,
notYetUpdatedAtSource = false
): string
```
**After**
```js
addOrUpdateSegmentation(
segmentationInput: SegmentationPublicInput | Partial<Segmentation>
)
```
### Data Structure Changes
The segmentation object that was used previously was a custom segmentation object that was used internally by the SegmentationService. But
we have moved to the cornerstone public segmentation input type.
**Before:**
```js
const segmentation = {
id: 'segmentation1',
type: SegmentationRepresentations.Labelmap,
isActive: true,
activeSegmentIndex: 1,
segments: [
{
segmentIndex: 1,
color: [255, 0, 0],
isVisible: true,
isLocked: false,
opacity: 255
}
],
label: 'Segmentation 1',
cachedStats: {},
representationData: {
LABELMAP: {
volumeId: 'volume1',
referencedVolumeId: 'reference1'
}
}
};
```
**After:**
This matches the cornerstone public segmentation input type.
```js
const segmentationInput = {
segmentationId: 'segmentation1',
representation: {
type: SegmentationRepresentations.Labelmap,
data: {
imageIds: segmentationImageIds,
referencedVolumeId: 'reference1'
}
},
config: {
label: 'Segmentation 1',
segments: {
1: {
label: 'Segment 1',
active: true,
locked: false
}
}
}
};
```
<details>
<summary>Migration Examples</summary>
```js
// Before
const newSegmentation = {
id: 'seg1',
type: SegmentationRepresentations.Labelmap,
segments: [...],
representationData: {
LABELMAP: {
volumeId: 'volume1',
referencedVolumeId: 'reference1'
}
}
};
segmentationService.addOrUpdateSegmentation(newSegmentation);
// After
segmentationService.addOrUpdateSegmentation({
segmentationId: 'seg1',
representation: {
type: SegmentationRepresentations.Labelmap,
data: {
imageIds: segmentationImageIds,
referencedVolumeId: 'reference1'
}
},
config: {
segments: {
1: {
label: 'Segment 1',
active: true
}
}
}
});
```
**Updating Existing Segmentation**
```js
// Before
const updatedSegmentation = {
...existingSegmentation,
segments: [...modifiedSegments],
activeSegmentIndex: 2
};
segmentationService.addOrUpdateSegmentation(updatedSegmentation);
// After
segmentationService.addOrUpdateSegmentation({
segmentationId: 'seg1',
config: {
segments: {
2: { active: true },
}
}
});
```
</details>
## loadSegmentationsForViewport
same as addOrUpdateSegmentation, you should pass in the new segmentation data structure.
For instance
**Before**
```js
const segmentations = [
{
id: '1',
label: 'Segmentations',
segments: labels.map((label, index) => ({
segmentIndex: index + 1,
label
})),
isActive: true,
activeSegmentIndex: 1,
},
];
commandsManager.runCommand('loadSegmentationsForViewport', {
segmentations,
});
```
**After**
```js
const labels = ['Segment 1', 'Segment 2', 'Segment 3'];
const segmentations = [
{
segmentationId: '1',
representation: {
type: Enums.SegmentationRepresentations.Labelmap,
},
config: {
label: 'Segmentations',
segments: labels.reduce((acc, label, index) => {
acc[index + 1] = {
label,
active: index === 0, // First segment is active
locked: false,
};
return acc;
}, {}),
},
},
];
commandsManager.runCommand('loadSegmentationsForViewport', {
segmentations,
});
```
---
## highlightSegment
**Before (OHIF 3.8)**
```js
// Before (v1.x)
highlightSegment(
segmentationId: string,
segmentIndex: number,
toolGroupId?: string,
alpha = 0.9,
animationLength = 750,
hideOthers = true,
highlightFunctionType = 'ease-in-out'
)
```
**After (OHIF 3.9)**
```js
highlightSegment(
segmentationId: string,
segmentIndex: number,
viewportId?: string, // notice viewportId instead of toolGroupId
alpha = 0.9,
animationLength = 750,
hideOthers = true,
highlightFunctionType = 'ease-in-out'
)
```
<details>
<summary>Key Changes</summary>
1. Removed `toolGroupId` in favor of `viewportId`
2. If no viewportId is provided, highlights in all relevant viewports
</details>
<details>
<summary>Migration Examples</summary>
**Basic Usage**
```js
// Before
segmentationService.highlightSegment(
'seg1',
1,
'toolGroup1',
0.9,
750,
true,
);
// After
segmentationService.highlightSegment(
'seg1',
1,
'viewport1',
0.9,
750,
true
);
```
**Highlighting in Multiple Views**
```js
// Before
const toolGroupIds = ['toolGroup1', 'toolGroup2'];
toolGroupIds.forEach(toolGroupId => {
segmentationService.highlightSegment(
'seg1',
1,
toolGroupId
);
});
// After - Method 1: Let service handle multiple viewports
segmentationService.highlightSegment('seg1', 1);
// After - Method 2: Explicitly specify viewports
const viewportIds = ['viewport1', 'viewport2'];
viewportIds.forEach(viewportId => {
segmentationService.highlightSegment(
'seg1',
1,
viewportId
);
});
```
</details>
---
## jumpToSegmentCenter
**Before (OHIF 3.8)**
```js
jumpToSegmentCenter(
segmentationId: string,
segmentIndex: number,
toolGroupId?: string,
highlightAlpha = 0.9,
highlightSegment = true,
animationLength = 750,
highlightHideOthers = false,
highlightFunctionType = 'ease-in-out'
)
```
**After (OHIF 3.9)**
```js
jumpToSegmentCenter(
segmentationId: string,
segmentIndex: number,
viewportId? string, // notice viewportId instead of toolGroupId
highlightAlpha = 0.9,
highlightSegment = true,
animationLength = 750,
highlightHideOthers = false,
highlightFunctionType = 'ease-in-out'
)
```
<details>
<summary>Key Changes</summary>
1. Removed `toolGroupId` parameter infavor of viewportId
2. Automatically handles relevant viewports if `viewportId` not provided
```
// Before
segmentationService.jumpToSegmentCenter(
'seg1',
1,
'toolGroup1'
);
// After
segmentationService.jumpToSegmentCenter(
'seg1',
1,
'viewportId1'
);
```
</details>
@@ -0,0 +1,11 @@
---
id: segmentation-index
title: Segmentation
sidebar_position: 1
---
:::info
This migration involves significant architectural changes to the segmentation system. While we typically aim for incremental updates, the shift from a tool group-centric to a viewport-centric architecture was necessary to support OHIF 3.9's advanced visualization capabilities, and more flexible segmentation handling.
Don't worry - we'll guide you through each change step by step!
:::