@cornerstonejs/tools
triggerAnnotationRenderForViewportIds
现在只需要 viewportIds
,不再需要 renderingEngine
。
triggerAnnotationRenderForViewportIds(renderingEngine, viewportIds) ---> triggerAnnotationRenderForViewportIds(viewportIds)
Details
为什么?
因为每个视口都有一个渲染引擎,因此不需要将渲染引擎作为参数传递。工具
StackScrollMouseWheelTool -> StackScrollTool
我们已经将鼠标滚轮与工具本身解耦,使其可以像其他鼠标绑定一样应用为绑定。
此更改带来了多个优势:
- 它可以与其他鼠标绑定组合使用
- 它可以与键盘绑定配对使用
- 之前 📦
- 之后 🚀🚀
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
getTargetVolumeId
方法已被移除,取而代之的是 getTargetId
,而 getTargetIdImage
已重命名为 getTargetImageData
,以更清楚地表明它是图像数据。
使用示例
- 之前 📦
- 之后 🚀
const volumeId = this.getTargetVolumeId(viewport);
const imageData = this.getTargetIdImage(targetId, renderingEngine);
const imageData = this.getTargetImageData(targetId);
新的分割模型
我们有一个新的分割模型,更加灵活且易于使用。
相同术语,不同架构
在 Cornerstone3D 版本 2 中,我们对分割模型进行了重大架构更改,同时保持了熟悉的术语。此重新设计旨在为在不同视口中处理分割提供更灵活和直观的方法。以下是主要更改及其背后的原因:
-
视口特定,而非基于工具组:
- 以前:分割与工具组绑定,工具组通常由多个视口组成。当用户希望在同一工具组内为某些视口添加分割而不是其他视口时,这会带来复杂性。
- 现在:分割现在是视口特定的。用户可以直接向视口添加分割,而不是向工具组添加或移除表示。这为每个视口渲染的内容提供了更细致的控制。
- 为什么:我们发现将渲染绑定到工具组并不是一种有效的方法。它通常需要为特定视口创建额外的工具组以进行自定义或防止渲染。
-
简化分割表示的识别:
- 以前:需要一个唯一的
segmentationRepresentationUID
进行识别。 - 现在:分割表示通过
segmentationId
和表示type
的组合进行识别。这允许每个视口对同一分割有不同的表示。 - 为什么:这种简化使得在不同视口中管理和引用分割表示更加容易。
- 以前:需要一个唯一的
-
数据与可视化的解耦:
- 以前:分割渲染与工具组紧密耦合。
- 现在:分割现在纯粹作为数据处理,与用于交互的工具分离。
- 为什么:虽然将工具绑定到工具组是合适的,但像分割渲染这样的视口特定功能应该由各个视口负责。这种分离允许在不同视口中有更灵活的渲染和交互选项。
-
多态分割支持:
- 新架构更好地支持多态分割的概念,即单个分割可以有多个表示(例如,标签图、轮廓、表面),并且可以在它们之间高效地转换。
- 为什么:这种灵活性允许更高效地存储、分析和实时可视化分割。
-
跨表示类型的一致 API:
- 新的 API 提供了一种统一的方式来处理不同的分割表示,使得管理涉及多个视口和表示类型的复杂场景更加容易。
- 为什么:这种一致性简化了开发,并减少了在处理不同分割类型时出错的可能性。
这些架构更改为处理分割提供了更坚实的基础,特别是在复杂的多视口场景中。新方法已被证明非常有效,并为未来的增强功能打开了可能性。虽然核心概念保持相似,但您在代码中与分割交互的方式将会显著改变。本迁移指南将引导您完成这些更改,提供前后示例,帮助您将现有代码库更新到新架构。
分割状态
Segmentation
类型已被重组,以更好地组织分割信息和表示数据。在讨论迁移指南之前,让我们先看看更改。
- 之前 📦
- 之后 🚀🚀
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;
};
新的分割状态模型提供了更有组织的数据结构。以前分散的信息,如 cachedStats
、segmentLabels
和 activeSegmentIndex
,已被整合到 segments
属性下。这种重组增强了清晰度和效率。在接下来的部分中,我们将讨论迁移指南,解释如何在新结构中访问和修改这些属性。这种重组主要影响分割存储级别。
表示数据键
SegmentationRepresentations
枚举已更新为使用标题大小写而不是全大写,以使其与其他枚举保持一致。
- 之前 📦
- 之后 🚀🚀
enum SegmentationRepresentations {
Labelmap = 'LABELMAP',
Contour = 'CONTOUR',
Surface = 'SURFACE',
}
enum SegmentationRepresentations {
Labelmap = 'Labelmap',
Contour = 'Contour',
Surface = 'Surface',
}
triggerAnnotationRenderForViewportIds
现在只需要 viewportIds
,不再需要 renderingEngine
。
triggerAnnotationRenderForViewportIds(renderingEngine, viewportIds) ---> triggerAnnotationRenderForViewportIds(viewportIds)
Details
为什么?
因为每个视口都有一个渲染引擎,因此不需要将渲染引擎作为参数传递。工具
StackScrollMouseWheelTool -> StackScrollTool
我们已经将鼠标滚轮与工具本身解耦,使其可以像其他鼠标绑定一样应用为绑定。
此更改带来了多个优势:
- 它可以与其他鼠标绑定组合使用
- 它可以与键盘绑定配对使用
- 之前 📦
- 之后 🚀🚀
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
getTargetVolumeId
方法已被移除,取而代之的是 getTargetId
,而 getTargetIdImage
已重命名为 getTargetImageData
,以更清楚地表明它是图像数据。
使用示例
- 之前 📦
- 之后 🚀
const volumeId = this.getTargetVolumeId(viewport);
const imageData = this.getTargetIdImage(targetId, renderingEngine);
const imageData = this.getTargetImageData(targetId);
新的分割模型
我们有一个新的分割模型,更加灵活且易于使用。
相同术语,不同架构
在 Cornerstone3D 版本 2 中,我们对分割模型进行了重大架构更改,同时保持了熟悉的术语。此重新设计旨在为在不同视口中处理分割提供更灵活和直观的方法。以下是主要更改及其背后的原因:
-
视口特定,而非基于工具组:
- 以前:分割与工具组绑定,工具组通常由多个视口组成。当用户希望在同一工具组内为某些视口添加分割而不是其他视口时,这会带来复杂性。
- 现在:分割现在是视口特定的。用户可以直接向视口添加分割,而不是向工具组添加或移除表示。这为每个视口渲染的内容提供了更细致的控制。
- 为什么:我们发现将渲染绑定到工具组并不是一种有效的方法。它通常需要为特定视口创建额外的工具组以进行自定义或防止渲染。
-
简化分割表示的识别:
- 以前:需要一个唯一的
segmentationRepresentationUID
进行识别。 - 现在:分割表示通过
segmentationId
和表示type
的组合进行识别。这允许每个视口对同一分割有不同的表示。 - 为什么:这种简化使得在不同视口中管理和引用分割表示更加容易。
- 以前:需要一个唯一的
-
数据与可视化的解耦:
- 以前: 分割渲染与工具组紧密耦合。
- 现在:分割现在纯粹作为数据处理,与用于交互的工具分离。
- 为什么:虽然将工具绑定到工具组是合适的,但像分割渲染这样的视口特定功能应该由各个视口负责。这种分离允许在不同视口中有更灵活的渲染和交互选项。
-
多态分割支持:
- 新架构更好地支持多态分割的概念,即单个分割可以有多个表示(例如,标签图、轮廓、表面),并且可以在它们之间高效地转换。
- 为什么:这种灵活性允许更高效地存储、分析和实时可视化分割。
-
跨表示类型的一致 API:
- 新的 API 提供了一种统一的方式来处理不同的分割表示,使得管理涉及多个视口和表示类型的复杂场景更加容易。
- 为什么:这种一致性简化了开发,并减少了在处理不同分割类型时出错的可能性。
这些架构更改为处理分割提供了更坚实的基础,特别是在复杂的多视口场景中。新方法已被证明非常有效,并为未来的增强功能打开了可能性。虽然核心概念保持相似,但您在代码中与分割交互的方式将会显著改变。本迁移指南将引导您完成这些更改,提供前后示例,帮助您将现有代码库更新到新架构。
分割状态
Segmentation
类型已被重组,以更好地组织分割信息和表示数据。在讨论迁移指南之前,让我们先看看更改。
- 之前 📦
- 之后 🚀🚀
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;
};
新的分割状态模型提供了更有组织的数据结构。以前分散的信息,如 cachedStats
、segmentLabels
和 activeSegmentIndex
,已被整合到 segments
属性下。这种重组增强了清晰度和效率。在接下来的部分中,我们将讨论迁移指南,解释如何在新结构中访问和修改这些属性。这种重组主要影响分割存储级别。
表示数据键
SegmentationRepresentations
枚举已更新为使用标题大小写而不是全大写,以使其与其他枚举保持一致。
- 之前 📦
- 之后 🚀🚀
enum SegmentationRepresentations {
Labelmap = 'LABELMAP',
Contour = 'CONTOUR',
Surface = 'SURFACE',
}
enum SegmentationRepresentations {
Labelmap = 'Labelmap',
Contour = 'Contour',
Surface = 'Surface',
}
这项更改影响了表示数据的访问方式:
- 之前 📦
- 之后 🚀🚀
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;
分割表示
表示结构已被简化,现在是视口特定的。
- 之前 📦
- 之后 🚀🚀
type ToolGroupSpecificRepresentation =
| ToolGroupSpecificLabelmapRepresentation
| ToolGroupSpecificContourRepresentation;
type ToolGroupSpecificRepresentationState = {
segmentationRepresentationUID: string;
segmentationId: string;
type: Enums.SegmentationRepresentations;
active: boolean;
segmentsLocked: 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>;
};
};
以前,分割表示是基于工具组的,这导致了一些问题。在新的结构中,分割表示是视口特定的。它现在由 segmentationId
、type
以及该分割的各种设置组成。由于这一变化,几个函数被移除或修改。以下是更改的总结:
移除的函数
getDefaultSegmentationStateManager
getSegmentationRepresentations
getAllSegmentationRepresentations
getSegmentationIdRepresentations
findSegmentationRepresentationByUID
getToolGroupIdsWithSegmentation
getToolGroupSpecificConfig
setToolGroupSpecificConfig
getGlobalConfig
setGlobalConfig
setSegmentationRepresentationSpecificConfig
getSegmentationRepresentationSpecificConfig
getSegmentSpecificRepresentationConfig
setSegmentSpecificRepresentationConfig
getToolGroupIdFromSegmentationRepresentationUID
addSegmentationRepresentation
getSegmentationRepresentationByUID
新的函数
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()
移除 SegmentationDisplayTool
不再需要将 SegmentationDisplayTool 添加到 toolGroup。
之前
toolGroup2.addTool(SegmentationDisplayTool.toolName);
toolGroup1.setToolEnabled(SegmentationDisplayTool.toolName);
现在
// 无需任何操作
堆栈标签图
要创建堆栈标签图,您不再需要手动在标签图 imageIds 和视口 imageIds 之间创建引用。我们现在为您自 动处理此过程。
这需要一个长篇的为什么...
以前的模型要求用户提供一个 imageIdReferenceMap,将标签图 imageIds 链接到视口 imageIds。这种方法在实现高级分割用例时带来了几个挑战:
-
手动创建映射容易出错,特别是在 imageIds 的顺序方面。
-
一旦分割与特定的视口 imageIds 相关联,就很难在其他地方渲染。例如:
- 在单个关键图像上渲染 CT 图像堆栈分割。
- 在包含 CT 和其他图像的堆栈上渲染 CT 图像堆栈分割。
- 在能量 1 上渲染 DX 双能分割到能量 2。
- 在同一空间的 PT 标签图上从堆栈视口渲染 CT 标签图。
这些场景突显了以前模型的局限性。
我们现在已经过渡到一个系统,用户只需提供 imageIds。在渲染过程中,我们将视口的当前 imageId 与标签图 imageIds 进行匹配,如果有匹配项,则渲染分割。这个匹配过程发生在 SegmentationStateManager 中,条件是分割必须与引用的视口处于同一平面。
这种新方法启用了许多额外的用例,并为分割渲染提供了更大的灵活性。
- 之前 📦
- 之后 🚀🚀
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,
},
},
},
]);
triggerAnnotationRenderForViewportIds
现在只需要 viewportIds
,不再需要 renderingEngine
。
triggerAnnotationRenderForViewportIds(renderingEngine, viewportIds) ---> triggerAnnotationRenderForViewportIds(viewportIds)
Details
为什么?
因为每个视口都有一个渲染引擎,因此不需要将渲染引擎作为参数传递。工具
StackScrollMouseWheelTool -> StackScrollTool
我们已经将鼠标滚轮与工具本身解耦,使其可以像其他鼠标绑定一样应用为绑定。
此更改带来了多个优势:
- 它可以与其他鼠标绑定组合使用
- 它可以与键盘绑定配对使用
- 之前 📦
- 之后 🚀🚀
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
getTargetVolumeId
方法已被移除,取而代之的是 getTargetId
,而 getTargetIdImage
已重命名为 getTargetImageData
,以更清楚地表明它是图像数据。
使用示例
- 之前 📦
- 之后 🚀
const volumeId = this.getTargetVolumeId(viewport);
const imageData = this.getTargetIdImage(targetId, renderingEngine);
const imageData = this.getTargetImageData(targetId);
新的分割模型
我们有一个新的分割模型,更加灵活且易于使用。
相同术语,不同架构
在 Cornerstone3D 版本 2 中,我们对分割模型进行了重大架构更改,同时保持了熟悉的术语。此重新设计旨在为在不同视口中处理分割提供更灵活和直观的方法。以下是主要更改及其背后的原因:
-
视口特定,而非基于工具组:
- 以前:分割与工具组绑定,工具组通常由多个视口组成。当用户希望在同一工具组内为某些视口添加分割而不是其他视口时,这会带来复杂性。
- 现在:分割现在是视口特定的。用户可以直接向视口添加分割,而不是向工具组添加或移除表示。这为每个视口渲染的内容提供了更细致的控制。
- 为什么:我们发现将渲染绑定到工具组并不是一种有效的方法。它通常需要为特定视口创建额外的工具组以进行自定义或防止渲染。
-
简化分割表示的识别:
- 以前:需要一个唯一的
segmentationRepresentationUID
进行识别。 - 现在:分割表示通过
segmentationId
和表示type
的组合进行识别。这允许每个视口对同一分割有不同的表示。 - 为什么:这种简化使得在不同视口中管理和引用分割表示更加容易。
- 以前:需要一个唯一的
-
数据与可视化的解耦:
- 以前:分割渲染与工具组紧密耦合。
- 现在:分割现在纯粹作为数据处理,与用于交互的工具分离。
- 为什么:虽然将工具绑定到工具组是合适的,但像分割渲染这样的视口特定功能应该由各个视口负责。这种分离允许在不同视口中有更灵活的渲染和交互选项。
-
多态分割支持:
- 新架构更好地支持多态分割的概念,即单个分割可以有多个表示(例如,标签图、轮廓、表面),并且可以在它们之间高效地转换。
- 为什么:这种灵活性允许更高效地存储、分析和实时可视化分割。
-
跨表示类型的一致 API:
- 新的 API 提供了一种统一的方式来处理不同的分割表示,使得管理涉及多个视口和表示类型的复杂场景更加容易。
- 为什么:这种一致性简化了开发,并减少了在处理不同分割类型时出错的可能性。
这些架构更改为处理分割提供了更坚实的基础,特别是在复杂的多视口场景中。新方法已被证明非常有效,并为未来的增强功能打开了可能性。虽然核心概念保持相似,但您在代码中与分割交互的方式将会显著改变。本迁移指南将引导您完成这些更改,提供前后示例,帮助您将现有代码库更新到新架构。
分割状态
Segmentation
类型已被重组,以更好地组织分割信息和表示数据。在讨论迁移指南之前,让我们先看看更改。
- 之前 📦
- 之后 🚀🚀
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;
};
新的分割状态模型提供了更有组织的数据结构。以前分散的信息,如 cachedStats
、segmentLabels
和 activeSegmentIndex
,已被整合到 segments
属性下。这种重组增强了清晰度和效率。在接下来的部分中,我们将讨论迁移指南,解释如何在新结构中访问和修改这些属性。这种重组主要影响分割存储级别。
表示数据键
SegmentationRepresentations
枚举已更新为使用标题大小写而不是全大写,以使其与其他枚举保持一致。
- 之前 📦
- 之后 🚀🚀
enum SegmentationRepresentations {
Labelmap = 'LABELMAP',
Contour = 'CONTOUR',
Surface = 'SURFACE',
}
enum SegmentationRepresentations {
Labelmap = 'Labelmap',
Contour = 'Contour',
Surface = 'Surface',
}
这项更改影响了表示数据的访问方式:
- 之前 📦
- 之后 🚀🚀
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;
分割表示
表示结构已被简化,现在是视口特定的。
- 之前 📦
- 之后 🚀🚀
type ToolGroupSpecificRepresentation =
| ToolGroupSpecificLabelmapRepresentation
| ToolGroupSpecificContourRepresentation;
type ToolGroupSpecificRepresentationState = {
segmentationRepresentationUID: string;
segmentationId: string;
type: Enums.SegmentationRepresentations;
active: boolean;
segmentsLocked: 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>;
};
};
以前,分割表示是基于工具组的,这导致了一些问题。在新的结构中,分割表示是视口特定的。它现在由 segmentationId
、type
以及该分割的各种设置组成。由于这一变化,几个函数被移除或修改。以下是更改的总结:
移除的函数
getDefaultSegmentationStateManager
getSegmentationRepresentations
getAllSegmentationRepresentations
getSegmentationIdRepresentations
findSegmentationRepresentationByUID
getToolGroupIdsWithSegmentation
getToolGroupSpecificConfig
setToolGroupSpecificConfig
getGlobalConfig
setGlobalConfig
setSegmentationRepresentationSpecificConfig
getSegmentationRepresentationSpecificConfig
getSegmentSpecificRepresentationConfig
setSegmentSpecificRepresentationConfig
getToolGroupIdFromSegmentationRepresentationUID
addSegmentationRepresentation
getSegmentationRepresentationByUID
新的函数
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()
移除 SegmentationDisplayTool
不再需要将 SegmentationDisplayTool 添加到 toolGroup。
之前
toolGroup2.addTool(SegmentationDisplayTool.toolName);
toolGroup1.setToolEnabled(SegmentationDisplayTool.toolName);
现在
// 无需任何操作
堆栈标签图
要创建堆栈标签图,您不再需要手动在标签图 imageIds 和视口 imageIds 之间创建引用。我们现在为您自动处理此过程。
这需要一个长篇的为什么...
以前的模型要求用户提供一个 imageIdReferenceMap,将标签图 imageIds 链接到视口 imageIds。这种方法在实现高级分割用例时带来了几个挑战:
-
手动创建映射容易出错,特别是在 imageIds 的顺序方面。
-
一旦分割与特定的视口 imageIds 相关联,就很难在其他地方渲染。例如:
- 在单个关键图像上渲染 CT 图像堆栈分割。
- 在包含 CT 和其他图像的堆栈上渲染 CT 图像堆栈分割。
- 在能量 1 上渲染 DX 双能分割到能量 2。
- 在同一空间的 PT 标签图上从堆栈视口渲染 CT 标签图。
这些场景突显了以前模型的局限性。
我们现在已经过渡到一个系统,用户只需提供 imageIds。在渲染过程中,我们将视口的当前 imageId 与标签图 imageIds 进行匹配,如果有匹配项,则渲染分割。这个匹配过程发生在 SegmentationStateManager 中,条件是分割必须与引用的视口处于同一平面。
这种新方法启用了许多额外的用例,并为分割渲染提供了更大的灵活性。
- 之前 📦
- 之后 🚀🚀
segmentation.addSegmentations([
{
segmentationId,
representation: {
type: csToolsEnums.SegmentationRepresentations.Labelmap,
data: {
imageIdReferenceMap:
cornerstoneTools.utilities.segmentation.createImageIdReferenceMap(
imageIds,
segmentationImageIds
),
},
},
},
]);
// 在这里填写“之后”部分的代码
triggerAnnotationRenderForViewportIds
现在只需要 viewportIds
,不再需要 renderingEngine
。
triggerAnnotationRenderForViewportIds(renderingEngine, viewportIds) ---> triggerAnnotationRenderForViewportIds(viewportIds)
Details
为什么?
因为每个视口都有一个渲染引擎,因此不需要将渲染引擎作为参数传递。工具
StackScrollMouseWheelTool -> StackScrollTool
我们已经将鼠标滚轮与工具本身解耦,使其可以像其他鼠标绑定一样应用为绑定。
此更改带来了多个优势:
- 它可以与其他鼠标绑定组合使用
- 它可以与键盘绑定配对使用
- 之前 📦
- 之后 🚀🚀
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
getTargetVolumeId
方法已被移除,取而代之的是 getTargetId
,而 getTargetIdImage
已重命名为 getTargetImageData
,以更清楚地表明它是图像数据。
使用示例
- 之前 📦
- 之后 🚀
const volumeId = this.getTargetVolumeId(viewport);
const imageData = this.getTargetIdImage(targetId, renderingEngine);
const imageData = this.getTargetImageData(targetId);
新的分割模型
我们有一个新的分割模型,更加灵活且易于使用。
相同术语,不同架构
在 Cornerstone3D 版本 2 中,我们对分割模型进行了重大架构更改,同时保持了熟悉的术语。此重新设计旨在为在不同视口中处理分割提供更灵活和直观的方法。以下是主要更改及其背后的原因:
-
视口特定,而非基于工具组:
- 以前:分割与工具组绑定,工具组通常由多个视口组成。当用户希望在同一工具组内为某些视口添加分割而不是其他视口时,这会带来复杂性。
- 现在:分割现在是视口特定的。用户可以直接向视口添加分割,而不是向工具组添加或移除表示。这为每个视口渲染的内容提供了更细致的控制。
- 为什么:我们发现将渲染绑定到工具组并不是一种有效的方法。它通常需要为特定视口创建额外的工具组以进行自定义或防止渲染。
-
简化分割 表示的识别:
- 以前:需要一个唯一的
segmentationRepresentationUID
进行识别。 - 现在:分割表示通过
segmentationId
和表示type
的组合进行识别。这允许每个视口对同一分割有不同的表示。 - 为什么:这种简化使得在不同视口中管理和引用分割表示更加容易。
- 以前:需要一个唯一的
-
数据与可视化的解耦:
- 以前:分割渲染与工具组紧密耦合。
- 现在:分割现在纯粹作为数据处理,与用于交互的工具分离。
- 为什么:虽然将工具绑定到工具组是合适的,但像分割渲染这样的视口特定功能应该由各个视口负责。这种分离允许在不同视口中有更灵活的渲染和交互选项。
-
多态分割支持:
- 新架构更好地支持多态分割的概念,即单个分割可以有多个表示(例如,标签图、轮廓、表面),并且可以在它们之间高效地转换。
- 为什么:这种灵活性允许更高效地存储、分析和实时可视化分割。
-
跨表示类型的一致 API:
- 新的 API 提供了一种统一的方式来处理不同的分割表示,使得管理涉及多个视口和表示类型的复杂场景更加容易。
- 为什么:这种一致性简化了开发,并减少了在处理不同分割类型时出错的可能性。
这些架构更改为处理分割提供了更坚实的基础,特别是在复杂的多视口场景中。新方法已被证明非常有效,并为未来的增强功能打开了可能性。虽然核心概念保持相似,但您在代码中与分割交互的方式将会显著改变。本迁移指南将引导您完成这些更改,提供前后示例,帮助您将现有代码库更新到新架构。
分割状态
Segmentation
类型已被重组,以更好地组织分割信息和表示数据。在讨论迁移指南之前,让我们先看看更改。
- 之前 📦
- 之后 🚀🚀
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;
};
新的分割状态模型提供了更有组织的数据结构。以前分散的信息,如 cachedStats
、segmentLabels
和 activeSegmentIndex
,已被整合到 segments
属性下。这种重组增强了清晰度和效率。在接下来的部分中,我们将讨论迁移指南,解释如何在新结构中访问和修改这些属性。这种重组主要影响分割存储级别。
表示数据键
SegmentationRepresentations
枚举已更新为使用标题大小写而不是全大写,以使其与其他枚举保持一致。
- 之前 📦
- 之后 🚀🚀
enum SegmentationRepresentations {
Labelmap = 'LABELMAP',
Contour = 'CONTOUR',
Surface = 'SURFACE',
}
enum SegmentationRepresentations {
Labelmap = 'Labelmap',
Contour = 'Contour',
Surface = 'Surface',
}
这项更改影响了表示数据的访问方式:
- 之前 📦
- 之后 🚀🚀
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;
分割表示
表示结构已被简化,现在是视口特定的。
- 之前 📦
- 之后 🚀🚀
type ToolGroupSpecificRepresentation =
| ToolGroupSpecificLabelmapRepresentation
| ToolGroupSpecificContourRepresentation;
type ToolGroupSpecificRepresentationState = {
segmentationRepresentationUID: string;
segmentationId: string;
type: Enums.SegmentationRepresentations;
active: boolean;
segmentsLocked: 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>;
};
};
以前,分割表示是基于工具组的,这导致了一些问题。在新的结构中,分割表示是视口特定的。它现在由 segmentationId
、type
以及该分割的各种设置组成。由于这一变化,几个函数被移除或修改。以下是更改的总结:
移除的 函数
getDefaultSegmentationStateManager
getSegmentationRepresentations
getAllSegmentationRepresentations
getSegmentationIdRepresentations
findSegmentationRepresentationByUID
getToolGroupIdsWithSegmentation
getToolGroupSpecificConfig
setToolGroupSpecificConfig
getGlobalConfig
setGlobalConfig
setSegmentationRepresentationSpecificConfig
getSegmentationRepresentationSpecificConfig
getSegmentSpecificRepresentationConfig
setSegmentSpecificRepresentationConfig
getToolGroupIdFromSegmentationRepresentationUID
addSegmentationRepresentation
getSegmentationRepresentationByUID
新的函数
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()
移除 SegmentationDisplayTool
不再需要将 SegmentationDisplayTool 添加到 toolGroup。
之前
toolGroup2.addTool(SegmentationDisplayTool.toolName);
toolGroup1.setToolEnabled(SegmentationDisplayTool.toolName);
现在
// 无需任何操作
堆栈标签图
要创建堆栈标签图,您不再需要手动在标签图 imageIds 和视口 imageIds 之间创建引用。我们现在为您自动处理此过程。
这需要一个长篇的为什么...
以前的模型要求用户提供一个 imageIdReferenceMap,将标签图 imageIds 链接到视口 imageIds。这种方法在实现高级分割用例时带来了几个挑战:
-
手动创建映射容易出错,特别是在 imageIds 的顺序方面。
-
一旦分割与特定的视口 imageIds 相关联,就很难在其他地方渲染。例如:
- 在单个关键图像上渲染 CT 图像堆栈分割。
- 在包含 CT 和其他图像的堆栈上渲染 CT 图像堆栈分割。
- 在能量 1 上渲染 DX 双能分割到能量 2。
- 在同一空间的 PT 标签图上从堆栈视口渲染 CT 标签图。
这些场景突显了以前模型的局限性。
我们现在已经过渡到一个系统,用户只需提供 imageIds。在渲染过程中,我们将视口的当前 imageId 与标签图 imageIds 进行匹配,如果有匹配项,则渲染分割。这个匹配过程发生在 SegmentationStateManager 中,条件是分割必须与引用的视口处于同一平面。
这种新方法启用了许多额外的用例,并为分割渲染提供了更大的灵活性。
- 之前 📦
- 之后 🚀🚀
segmentation.addSegmentations([
{
segmentationId,
representation: {
type: csToolsEnums.SegmentationRepresentations.Labelmap,
data: {
imageIdReferenceMap:
cornerstoneTools.utilities.segmentation.createImageIdReferenceMap(
imageIds,
segmentationImageIds
),
},
},
},
]);
// 在这里填写“之后”部分的代码
迁移步骤:
- 将通用的
addSegmentationRepresentations
调用替换为适当的特定表示函数。 - 更新输入数组以匹配新的
RepresentationPublicInput
类型。 - 从代码中移除任何特定类型的逻辑,因为现在这些逻辑由这些新函数处理。
多视口函数
版本 2 引入了新的函数,用于同时向多个视口添加分割表示。
- 之前 📦
- 之后 🚀🚀
// 版本 1 中没有等效的函数
function addContourRepresentationToViewportMap(viewportInputMap: {
[viewportId: string]: RepresentationPublicInput[];
});
function addLabelmapRepresentationToViewportMap(viewportInputMap: {
[viewportId: string]: RepresentationPublicInput[];
});
function addSurfaceRepresentationToViewportMap(viewportInputMap: {
[viewportId: string]: RepresentationPublicInput[];
});
迁移步骤:
- 如果您之前向多个工具组添加表示,请重构代码以使用这些新的多视口函数。
- 创建一个
viewportInputMap
对象,将视口 ID 作为键,RepresentationPublicInput
数组作为值。 - 根据表示类型调用适当的多视口函数。
事件
由于我们从工具组转向视口,许多事件已被重命名,以包含 viewportId
而不是 toolGroupId
,并且
一些事件详情已更改为包含 segmentationId
而不是 segmentationRepresentationUID
或 toolGroupId
。
移除工具组特定事件
triggerSegmentationRepresentationModified
和 triggerSegmentationRepresentationRemoved
函数已被移除。取而代之的是,库现在使用更通用的方法来处理分割事件。
- 之前 📦
- 之后 🚀🚀
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 {
// ...
}
迁移步骤:
- 在函数调用中将
toolGroupId
替换为viewportId
。 - 将
segmentationRepresentationUID
替换为segmentationId
。 - 添加
type
参数以指定分割表示类型。
简化的分割修改事件
triggerSegmentationModified
函数已简化,始终需要一个 segmentationId
。
- 之前 📦
- 之后 🚀🚀
function triggerSegmentationModified(segmentationId?: string): void {
// ...
}
function triggerSegmentationModified(segmentationId: string): void {
// ...
}
迁移步骤:
- 确保在调用
triggerSegmentationModified
时始终提供segmentationId
。 - 移除任何处理
segmentationId
未定义情况的逻辑。
更新的事件详情类型
几个事件详情类型已更新,以反映分割系统中的更改:
- 之前 📦
- 之后 🚀🚀
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;
};
triggerAnnotationRenderForViewportIds
现在只需要 viewportIds
,不再需要 renderingEngine
。
triggerAnnotationRenderForViewportIds(renderingEngine, viewportIds) ---> triggerAnnotationRenderForViewportIds(viewportIds)
Details
为什么?
因为每个视口都有一个渲染引擎,因此不需要将渲染引擎作为参数传递。工具
StackScrollMouseWheelTool -> StackScrollTool
我们已经将鼠标滚轮与工具本身解耦,使其可以像其他鼠标绑定一样应用为绑定。
此更改带来了多个优势:
- 它可以与其他鼠标绑定组合使用
- 它可以与键盘绑定配对使用
- 之前 📦
- 之后 🚀🚀
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
getTargetVolumeId
方法已被移除,取而代之的是 getTargetId
,而 getTargetIdImage
已重命名为 getTargetImageData
,以更清楚地表明它是图像数据。
使用示例
- 之前 📦
- 之后 🚀
const volumeId = this.getTargetVolumeId(viewport);
const imageData = this.getTargetIdImage(targetId, renderingEngine);
const imageData = this.getTargetImageData(targetId);
新的分割模型
我们有一个新的分割模型,更加灵活且易于使用。
相同术语,不同架构
在 Cornerstone3D 版本 2 中,我们对分割模型进行了重大架构更改,同时保持了熟悉的术语。此重新设计旨在为在不同视口中处理分割提供更灵活和直观的方法。以下是主要更改及其背后的原因:
-
视口特定,而非基于工具组:
- 以前:分割与工具组绑定,工具组通常由多个视口组成。当用户希望在同一工具组内为某些视口添加分割而不是其他视口时,这会带来复杂性。
- 现在:分割现在是视口特定的。用户可以直接向视口添加分割,而不是向工具组添加或移除表示。这为每个视口渲染的内容提供了更细致的控制。
- 为什么:我们发现将渲染绑定到工具组并不是一种有效的方法。它通常需要为特定视口创建额外的工具组以进行自定义或防止渲染。
-
简化分割表示的识别:
- 以前:需要一个唯一的
segmentationRepresentationUID
进行识别。 - 现在:分割表示通过
segmentationId
和表示type
的组合进行识别。这允许每个视口对同一分割有不同的表示。 - 为什么:这种简化使得在不同视口中管理和引用分割表示更加容易。
- 以前:需要一个唯一的
-
数据与可视化的解耦:
- 以前:分割渲染与工具组紧密耦合。
- 现在:分割现在纯粹作为数据处理,与用于交互的工具分离。
- 为什么:虽然将工具绑定到工具组是合适的,但像分割渲染这样的视口特定功能应该由各个视口负责。这种分离允许在不同视口中有更灵活的渲染和交互选项。
-
多态分割支持:
- 新架构更好地支持多态分割的概念,即单个分割可以有多个表示(例如,标签图、轮廓、表面),并且可以在它们之间高效地转换。
- 为什么:这种灵活性允许更高效地存储、分析和实时可视化分割。
-
跨表示类型的一致 API:
- 新的 API 提供了一种统一的方式来处理不同的分割表示,使得管理涉及多个视口和表示类型的复杂场景更加容易。
- 为什么:这种一致性简化了开发,并减少了在处理不同分割类型时出错的可能性。
这些架构更改为处理分割提供了更坚实的基础,特别是在复杂的多视口场景中。新方法已被证明非常有效,并为未来的增强功能打开了可能性。虽然核心概念保持相似,但您在代码中与分割交互的方式将会显 著改变。本迁移指南将引导您完成这些更改,提供前后示例,帮助您将现有代码库更新到新架构。
分割状态
Segmentation
类型已被重组,以更好地组织分割信息和表示数据。在讨论迁移指南之前,让我们先看看更改。
- 之前 📦
- 之后 🚀🚀
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;
};
新的分割状态模型提供了更有组织的数据结构。以前分散的信息,如 cachedStats
、segmentLabels
和 activeSegmentIndex
,已被整合到 segments
属性下。这种重组增强了清晰度和效率。在接下来的部分中,我们将讨论迁移指南,解释如何在新结构中访问和修改这些属性。这种重组主要影响分割存储级别。
表示数据键
SegmentationRepresentations
枚举已更新为使用标题大小写而不是全大写,以使其与其他枚举保持一致。
- 之前 📦
- 之后 🚀🚀
enum SegmentationRepresentations {
Labelmap = 'LABELMAP',
Contour = 'CONTOUR',
Surface = 'SURFACE',
}
enum SegmentationRepresentations {
Labelmap = 'Labelmap',
Contour = 'Contour',
Surface = 'Surface',
}
这项更改影响了表示数据的访问方式:
- 之前 📦
- 之后 🚀🚀
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;
分割表示
表示结构已被简化,现在是视口特定的。
- 之前 📦
- 之后 🚀🚀
type ToolGroupSpecificRepresentation =
| ToolGroupSpecificLabelmapRepresentation
| ToolGroupSpecificContourRepresentation;
type ToolGroupSpecificRepresentationState = {
segmentationRepresentationUID: string;
segmentationId: string;
type: Enums.SegmentationRepresentations;
active: boolean;
segmentsLocked: 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>;
};
};
以前,分割表示是基于工具组的,这导致了一些问题。在新的结构中,分割表示是视口特定的。它现在由 segmentationId
、type
以及该分割的各种设置组成。由于这一变化,几个函数被移除或修改。以下是更改的总结:
移除的函数
getDefaultSegmentationStateManager
getSegmentationRepresentations
getAllSegmentationRepresentations
getSegmentationIdRepresentations
findSegmentationRepresentationByUID
getToolGroupIdsWithSegmentation
getToolGroupSpecificConfig
setToolGroupSpecificConfig
getGlobalConfig
setGlobalConfig
setSegmentationRepresentationSpecificConfig
getSegmentationRepresentationSpecificConfig
getSegmentSpecificRepresentationConfig
setSegmentSpecificRepresentationConfig
getToolGroupIdFromSegmentationRepresentationUID
addSegmentationRepresentation
getSegmentationRepresentationByUID
新的函数
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()
移除 SegmentationDisplayTool
不再需要将 SegmentationDisplayTool 添加到 toolGroup。
之前
toolGroup2.addTool(SegmentationDisplayTool.toolName);
toolGroup1.setToolEnabled(SegmentationDisplayTool.toolName);
现在
// 无需任何操作
堆栈标签图
要创建堆栈标签图,您不再需要手动在标签图 imageIds 和视口 imageIds 之间创建引用。我们现在为您自动处理此过程。
这需要一个长篇的为什么...
以前的模型要求用户提供一个 imageIdReferenceMap
,将标签图 imageIds 链接到视口 imageIds。这种方法在实现高级分割用例时带来了几个挑战:
-
手动创建映射容易出错,特别是在 imageIds 的顺序方面。
-
一旦分割与特定的视口 imageIds 相关联,就很难在其他地方渲染。例如:
- 在单个关键图像上渲染 CT 图像堆栈分割。
- 在包含 CT 和其他图像的堆栈上渲染 CT 图像堆栈分割。
- 在能量 1 上渲染 DX 双能分割到能量 2。
- 在同一空间的 PT 标签图上从堆栈视口渲染 CT 标签图。
这些场景突显了以前模型的局限性。
我们现在已经过渡到一个系统,用户只需提供 imageIds。在渲染过程中,我们将视口的当前 imageId 与标签图 imageIds 进行匹配,如果有匹配项,则渲染分割。这个匹配过程发生在 SegmentationStateManager 中,条件是分割必须与引用的视口处于同一平面。
这种新方法启用了许多额外的用例,并为分割渲染提供了更大的灵活性。
- 之前 📦
- 之后 🚀🚀
segmentation.addSegmentations([
{
segmentationId,
representation: {
type: csToolsEnums.SegmentationRepresentations.Labelmap,
data: {
imageIdReferenceMap:
cornerstoneTools.utilities.segmentation.createImageIdReferenceMap(
imageIds,
segmentationImageIds
),
},
},
},
]);
// 在这里填写“之后”部分的代码
迁移步骤:
- 将通用的
addSegmentationRepresentations
调用替换为适当的特定表示函数。 - 更新输入数组以匹配新的
RepresentationPublicInput
类型。 - 从代码中移除任何特定类型的逻辑,因为现在这些逻辑由这些新函数处理。
多视口函数
版本 2 引入了新的函数,用于同时向多个视口添加分割表示。
- 之前 📦
- 之后 🚀🚀
// 版本 1 中没有等效的函数
function addContourRepresentationToViewportMap(viewportInputMap: {
[viewportId: string]: RepresentationPublicInput[];
});
function addLabelmapRepresentationToViewportMap(viewportInputMap: {
[viewportId: string]: RepresentationPublicInput[];
});
function addSurfaceRepresentationToViewportMap(viewportInputMap: {
[viewportId: string]: RepresentationPublicInput[];
});
迁移步骤:
- 如果您之前向多个工具组添加表示,请重构代码以使用这些新的多视口函数。
- 创建一个
viewportInputMap
对象,将视口 ID 作为键,RepresentationPublicInput
数组作为值。 - 根据表示类型调用适当的多视口函数。
事件
由于我们从工具组转向视口,许多事件已被重命名,以包含 viewportId
而不是 toolGroupId
,并且
一些事件详情已更改为包含 segmentationId
而不是 segmentationRepresentationUID
或 toolGroupId
。
移除工具组特定事件
triggerSegmentationRepresentationModified
和 triggerSegmentationRepresentationRemoved
函数已被移除。取而代之的是,库现在使用更通用的方法来处理分割事件。
- 之前 📦
- 之后 🚀🚀
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 {
// ...
}
迁移步骤:
- 在函数调用中将
toolGroupId
替换为viewportId
。 - 将
segmentationRepresentationUID
替换为segmentationId
。 - 添加
type
参数以指定分割表示类型。
简化的分割修改事件
triggerSegmentationModified
函数已简化,始终需要一个 segmentationId
。
- 之前 📦
- 之后 🚀🚀
function triggerSegmentationModified(segmentationId?: string): void {
// ...
}
function triggerSegmentationModified(segmentationId: string): void {
// ...
}
迁移步骤:
- 确保在调 用
triggerSegmentationModified
时始终提供segmentationId
。 - 移除任何处理
segmentationId
未定义情况的逻辑。
更新的事件详情类型
几个事件详情类型已更新,以反映分割系统中的更改:
- 之前 📦
- 之后 🚀🚀
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;
};
triggerAnnotationRenderForViewportIds
现在只需要 viewportIds
,不再需要 renderingEngine
。
triggerAnnotationRenderForViewportIds(renderingEngine, viewportIds) ---> triggerAnnotationRenderForViewportIds(viewportIds)
Details
为什么?
因为每个视口都有一个渲染引擎,因此不需要将渲染引擎作为参数传递。工具
StackScrollMouseWheelTool -> StackScrollTool
我们已经将鼠标滚轮与工具本身解耦,使其可以像其他鼠标绑定一样应用为绑定。
此更改带来了多个优势:
- 它可以与其他鼠标绑定组合使用
- 它可以与键盘绑定配对使用
- 之前 📦
- 之后 🚀🚀
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
getTargetVolumeId
方法已被移除,取而代之的是 getTargetId
,而 getTargetIdImage
已重命名为 getTargetImageData
,以更清楚地表明它是图像数据。
使用示例
- 之前 📦
- 之后 🚀
const volumeId = this.getTargetVolumeId(viewport);
const imageData = this.getTargetIdImage(targetId, renderingEngine);
const imageData = this.getTargetImageData(targetId);
新的分割模型
我们有一个新的分割模型,更加灵活且易于使用。
相同术语,不同架构
在 Cornerstone3D 版本 2 中,我们对分割模型进行了重大架构更改,同时保持了熟悉的术语。此重新设计旨在为在不同视口中处理分割提供更灵活和直观的方法。以下是主要更改及其背后的原因:
-
视口特定,而非基于工具组:
- 以前:分割与工具组绑定,工具组通常由多个视口组成。当用户希望在同一工具组内为某些视口添加分割而不是其他视口时,这会带来复杂性。
- 现在:分割现在是视口特定的。用户可以直接向视口添加分割,而不是向工具组添加或移除表示。这为每个视口渲染的内容提供了更细致的控制。
- 为什么:我们发现将渲染绑定到工具组并不是一种有效的 方法。它通常需要为特定视口创建额外的工具组以进行自定义或防止渲染。
-
简化分割表示的识别:
- 以前:需要一个唯一的
segmentationRepresentationUID
进行识别。 - 现在:分割表示通过
segmentationId
和表示type
的组合进行识别。这允许每个视口对同一分割有不同的表示。 - 为什么:这种简化使得在不同视口中管理和引用分割表示更加容易。
- 以前:需要一个唯一的
-
数据与可视化的解耦:
- 以前:分割渲染与工具组紧密耦合。
- 现在:分割现在纯粹作为数据处理,与用于交互的工具分离。
- 为什么:虽然将工具绑定到工具组是合适的,但像分割渲染这样的视口特定功能应该由各个视口负责。这种分离允许在不同视口中有更灵活的渲染和交互选项。
-
多态分割支持:
- 新架构更好地支持多态分割的概念,即单个分割可以有多个表示(例如,标签图、轮廓、表面),并且可以在它们之间高效地转换。
- 为什么:这种灵活性允许更高效地存储、分析和实时可视化分割。
-
跨表示类型的一致 API:
- 新的 API 提供了一种统一的方式来处理不同的分割表示,使得管理涉及多个视口和表示类型的复杂场景更加容易。
- 为什么:这种一致性简化了开发,并减少了在处理不同分割类型时出错的可能性。
这些架构更改为处理分割提供了更坚实的基础,特别是在复杂的多视口场景中。新方法已被证明非常有效,并为未来的增强功能打开了可能 性。虽然核心概念保持相似,但您在代码中与分割交互的方式将会显著改变。本迁移指南将引导您完成这些更改,提供前后示例,帮助您将现有代码库更新到新架构。
分割状态
Segmentation
类型已被重组,以更好地组织分割信息和表示数据。在讨论迁移指南之前,让我们先看看更改。
- 之前 📦
- 之后 🚀🚀
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;
};
新的分割状态模型提供了更有组织的数据结构。以前分散的信息,如 cachedStats
、segmentLabels
和 activeSegmentIndex
,已被整合到 segments
属性下。这种重组增强了清晰度和效率。在接下来的部分中,我们将讨论迁移指南,解释如何在新结构中访问和修改这些属性。这种重组主要影响分割存储级别。
表示数据键
SegmentationRepresentations
枚举已更新为使用标题大小写而不是全大写,以使其与其他枚举保持一致。
- 之前 📦
- 之后 🚀🚀
enum SegmentationRepresentations {
Labelmap = 'LABELMAP',
Contour = 'CONTOUR',
Surface = 'SURFACE',
}
enum SegmentationRepresentations {
Labelmap = 'Labelmap',
Contour = 'Contour',
Surface = 'Surface',
}
这项更改影响了表示数据的访问方式:
- 之前 📦
- 之后 🚀🚀
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;
分割表示
表示结构已被简化,现在是视口特定的。
- 之前 📦
- 之后 🚀🚀
type ToolGroupSpecificRepresentation =
| ToolGroupSpecificLabelmapRepresentation
| ToolGroupSpecificContourRepresentation;
type ToolGroupSpecificRepresentationState = {
segmentationRepresentationUID: string;
segmentationId: string;
type: Enums.SegmentationRepresentations;
active: boolean;
segmentsLocked: 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>;
};
};
以前,分割表示是基于工具组的,这导致了一些问题。在新的结构中,分割表示是视口特定的。它现在由 segmentationId
、type
以及该分割的各种设置组成。由于这一变化, 几个函数被移除或修改。以下是更改的总结:
移除的函数
getDefaultSegmentationStateManager
getSegmentationRepresentations
getAllSegmentationRepresentations
getSegmentationIdRepresentations
findSegmentationRepresentationByUID
getToolGroupIdsWithSegmentation
getToolGroupSpecificConfig
setToolGroupSpecificConfig
getGlobalConfig
setGlobalConfig
setSegmentationRepresentationSpecificConfig
getSegmentationRepresentationSpecificConfig
getSegmentSpecificRepresentationConfig
setSegmentSpecificRepresentationConfig
getToolGroupIdFromSegmentationRepresentationUID
addSegmentationRepresentation
getSegmentationRepresentationByUID
新的函数
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()
移除 SegmentationDisplayTool
不再需要将 SegmentationDisplayTool 添加到 toolGroup。
之前
toolGroup2.addTool(SegmentationDisplayTool.toolName);
toolGroup1.setToolEnabled(SegmentationDisplayTool.toolName);
现在
// 无需任何操作
堆栈标签图
要创建堆栈标签图,您不再需要手动在标签图 imageIds 和视口 imageIds 之间创建引用。我们现在为您自动处理此过程。
这需要一个长篇的为什么...
以前的模型要求用户提供一个 imageIdReferenceMap
,将标签图 imageIds 链接到视口 imageIds。这种方法在实现高级分割用例时带来了几个挑战:
-
手动创建映射容易出错,特别是在 imageIds 的顺序方面。
-
一旦分割与特定的视口 imageIds 相关联,就很难在其他地方渲染。例如:
- 在单个关键图像上渲染 CT 图像堆栈分割。
- 在包含 CT 和其他图像的堆栈上渲染 CT 图像堆栈分割。
- 在能量 1 上渲染 DX 双能分割到能量 2。
- 在同一空间的 PT 标签图上从堆栈视口渲染 CT 标签图。
这些场景突显了以前模型的局限性。
我们现在已经过渡到一个系统,用户只需提供 imageIds。在渲染过程中,我们将视口的当前 imageId 与标签图 imageIds 进行匹配,如果有匹配项,则渲染分割。这个匹配过程发生在 SegmentationStateManager 中,条件是分割必须与引用的视口处于同一平面。
这种新方法启用了许多额外的用例,并为分割渲染提供了更大的灵活性。
- 之前 📦
- 之后 🚀🚀
segmentation.addSegmentations([
{
segmentationId,
representation: {
type: csToolsEnums.SegmentationRepresentations.Labelmap,
data: {
imageIdReferenceMap:
cornerstoneTools.utilities.segmentation.createImageIdReferenceMap(
imageIds,
segmentationImageIds
),
},
},
},
]);
// 在这里填写“之后”部分的代码
迁移步骤:
- 将通用的
addSegmentationRepresentations
调用替换为适当的特定表示函数。 - 更新输入数组以匹配新的
RepresentationPublicInput
类型。 - 从代码中移除任何特定类型的逻辑,因为现在这些逻辑由这些新函数处理。
多视口函数
版本 2 引入了新的函数,用于同时向多个视口添加分割表示。
- 之前 📦
- 之后 🚀 🚀
// 版本 1 中没有等效的函数
function addContourRepresentationToViewportMap(viewportInputMap: {
[viewportId: string]: RepresentationPublicInput[];
});
function addLabelmapRepresentationToViewportMap(viewportInputMap: {
[viewportId: string]: RepresentationPublicInput[];
});
function addSurfaceRepresentationToViewportMap(viewportInputMap: {
[viewportId: string]: RepresentationPublicInput[];
});
迁移步骤:
- 如果您之前向多个工具组添加表示,请重构代码以使用这些新的多视口函数。
- 创建一个
viewportInputMap
对象,将视口 ID 作为键,RepresentationPublicInput
数组作为值。 - 根据表示类型调用适当的多视口函数。
事件
由于我们从工具组转向视口,许多事件已被重命名,以包含 viewportId
而不是 toolGroupId
,并且
一些事件详情已更改为包含 segmentationId
而不是 segmentationRepresentationUID
或 toolGroupId
。