OHIF cornerstone-dicom-seg 扩展深度解析:DICOM SEG 读取、渲染与演进路线
【免费下载链接】ViewersOHIF zero-footprint DICOM viewer and oncology specific Lesion Tracker, plus shared extension packages项目地址: https://gitcode.com/GitHub_Trending/vi/Viewers
本技术指南以 OHIF Viewers 仓库中extensions/cornerstone-dicom-seg扩展及其 CHANGELOG.md 为主体,系统梳理该扩展在 DICOM SEG(分割对象)读取、体积标签图(Labelmap)渲染、SEG 视口、水合(Hydration)机制与定制化配置方面的完整实现与多年演进脉络。读者将掌握 SEG 扩展的模块组成与加载调用链、labelmap/bitmap 双解析器与存储配置、多帧 SEG 的性能优化策略,以及如何借助segmentation.*系列定制化项调整默认行为。
扩展定位与模块组成
cornerstone-dicom-seg是 OHIF 提供 DICOM SEG 读取工作流(read workflow)的官方扩展。根据其 README 的说明,该扩展允许在 OHIF 中加载 DICOM SEG 图像并显示:当前分割以体积标签图(volumetric labelmap)的形式加载,并作为 3D 体积渲染。扩展还提供一个 SEG 视口,用于渲染和审查 DICOM SEG 图像;如需完整加载所有分割段(segments),需要点击视口操作栏(viewport action bar)上的 SEG Pill 按钮以触发完整加载。
从扩展入口 index.tsx 可以看到,该扩展向 OHIF 注册了以下模块:
getViewportModule:注册名为dicom-seg的视口组件,底层通过React.lazy按需加载 OHIFCornerstoneSEGViewport.tsx,并注入servicesManager、extensionManager、commandsManager;getSopClassHandlerModule:为 SEG 系列提供 SopClassHandler,将系列转换为 DisplaySet;getHangingProtocolModule:提供 SEG 相关的挂片协议;getCommandsModule/getCustomizationModule/getToolbarModule:提供命令、定制化默认值与工具栏按钮。
SopClassHandler:从 DICOM SEG 系列到 DisplaySet
SEG 扩展的核心入口是 getSopClassHandlerModule.ts。该模块声明了两个 DICOM SOP Class UID:
const sopClassUids = ['1.2.840.10008.5.1.4.1.1.66.4', '1.2.840.10008.5.1.4.1.1.66.7']; const LABELMAP_SEG_SOP_CLASS_UID = '1.2.840.10008.5.1.4.1.1.66.7';其中1.2.840.10008.5.1.4.1.1.66.7是 Segmentation Storage(Label Map Segmentation,即标签图分割)SOP Class,1.2.840.10008.5.1.4.1.1.66.4是 Bitmap Segmentation(位图分割)SOP Class。二者均在本扩展的 segmentationConfig.ts 中被命名导出:
export const LABELMAP_SEG_SOP_CLASS_UID = '1.2.840.10008.5.1.4.1.1.66.7'; export const BITMAP_SEG_SOP_CLASS_UID = '1.2.840.10008.5.1.4.1.1.66.4';_getDisplaySetsFromSeries负责把 SEG 实例构造成 OHIF 的 DisplaySet,关键处理逻辑包括:
- 选择实例列表中最后一个实例(最近创建的)作为当前实例;
- 通过
utils.getLatestInstanceDateTime取实例日期时间作为 DisplaySet 日期时间; - 构造标记
isDerivedDisplaySet: true、isOverlayDisplaySet: true、isLoaded: false、isHydrated: false的派生 DisplaySet; - 从
instance.ReferencedSeriesSequence中解析被引用系列(referencedSeriesInstanceUID)与被引用图像(referencedImages); - 通过
displaySetService.getDisplaySetsForReferences找到被引用的 DisplaySet(即分割所叠加的灰度系列),若引用多个系列则默认取第一个并给出警告; - 当被引用 DisplaySet 尚不存在时,订阅
DISPLAY_SETS_ADDED事件,待被引用系列加入后回填referencedDisplaySetInstanceUID与FrameOfReferenceUID(处理 SEG 元数据中不含引用 UID 的常见情况); - 返回的 DisplaySet 携带
load函数,供上层按需调用。
加载链路:从网络字节到 Cornerstone3D 分割状态
DisplaySet 的load函数最终指向 getSopClassHandlerModule.ts 中的_load,其内部通过_loadSegments完成真正的解析,调用链可概括为:
- 去重:
_load维护loadPromises[SOPInstanceUID],若该 SEG 已在加载或已加载且分割已存在,直接返回同一个 Promise,避免重复网络请求。 - 解析器类型判定:
getSegmentationParserType(sopClassUID, customizationService)依据 SOP Class UID 返回labelmap或bitmap(详见 segmentationConfig.ts);未知类型时回退到存储默认模式。 - 被引用系列 imageId 解析:优先使用被引用 DisplaySet 缓存的
imageIds,其次通过 dataSource 的getImageIdsForDisplaySet扩展,最后回退到images.map(img => img.imageId)。 - 调用适配器解析:核心解析由
@cornerstonejs/adapters的adaptersSEG.Cornerstone3D.Segmentation.createFromDicomSegImageId完成,传入 metadataProvider、容差tolerance = 0.001、解析器类型、帧 imageId 列表与帧解码并发数。 - 颜色归一化:解析得到的每个分割段的
RecommendedDisplayCIELabValue(DICOM 标准推荐的 CIELab 显示色)通过dicomlabToRGB转为 RGBA;若缺失,则回退到CONSTANTS.COLOR_LUT调色板索引色,并通过uiNotificationService提示用户使用了默认颜色。 - 结果合并:
Object.assign(segDisplaySet, results)把解析出的segments、labelMapImageIds 等写回 DisplaySet,随后由segmentationService.createSegmentationForSEGDisplaySet创建 Cornerstone3D 分割状态。
整个加载过程通过eventTarget.addEventListener(Enums.Events.SEGMENTATION_LOAD_PROGRESS, onProgress)广播SEGMENT_LOADING_COMPLETE进度事件,供视口 UI 展示加载百分比;finally中移除监听并取消预取。
SEG 视口与"加载 / 水合"机制
OHIFCornerstoneSEGViewport.tsx 是 SEG 专属视口。其源码对"加载(loading)"与"水合(hydration)"做了明确区分:
- loading:SEG 数据经网络加载并对像素位进行解包(bit unpacking),即把 DICOM SEG 像素数据转换为可用 labelmap;
- hydration:SEG 被打开且所有分割段载入分割面板,并叠加渲染到所有与被引用系列处于同一
FrameOfReferenceUID的视口上。
视口通过useViewportGrid感知当前视口网格,为每个视口生成独立工具组SEGToolGroup-${viewportId}(见 initSEGToolGroup.ts),并将底层渲染委托给OHIFCornerstoneViewport,传入displaySets={[referencedDisplaySet, segDisplaySet]}——即底层堆栈使用被引用系列,SEG 作为叠加层(overlay)显示。这与扩展 README 中"SEG 作为体积 labelmap 加载并以 3D 体积显示"的描述一致:基础层是原始灰度系列,分割层是渲染在上的彩色 labelmap。
视口对"被引用 DisplaySet 缺失"的场景做了健壮性处理:当referencedDisplaySetInstanceUID不存在(例如直接以SeriesInstanceUID方式单独启动 SEG 系列),视口会尝试调用定制化项missingReferenceDisplaySetHandler;若未注册该处理器,则跳过 SEG 渲染并打印日志,避免视口崩溃。该能力在 3.12.0-beta.101(2025-12)的seg-viewport: add guard for missing reference display set handler to prevent viewport crash修复中被进一步加固。
多帧 SEG 与加载性能优化
多帧 SEG(multiframe SEG)支持是本扩展演进中的重要主题。源码中围绕多帧做了三处关键设计:
帧 imageId 展开。getFrameImageIds会把形如…/frames/1的 WADO-RS 帧 URL 展开为每帧一个 imageId;_resolveFrameImageIds在帧 URL 展开不适用时,则逐帧调用dataSource.getImageIdsForInstance({ instance, frame })获取各帧 imageId。
受控并发解码。源码中硬编码了帧解码并发上限:
// Max number of SEG frames fetched/decoded concurrently by the segmentation // loader. Hard-coded to 16 for now; intended to become configurable (and to // pair with the full-instance prefetch capability) in a follow-up. const SEG_FRAME_DECODE_CONCURRENCY = 16;该值作为concurrency参数传给createFromDicomSegImageId,避免成百上千个微小帧请求同时并发拖垮浏览器。
Part 10 整体预取。针对"SEG 帧太小太多、逐帧请求效率低下"的问题,加载器默认开启loadMultiframeAsPart10预取:将整个 SEG 实例作为单个 Part 10 DICOM 对象批量拉取,并把各帧压缩像素注册进 Cornerstone3D 的帧注册表,使后续逐帧加载直接命中本地而不再发起网络请求。该开关的取值优先级为:数据源配置dataSource.getConfig()?.loadMultiframeAsPart10> 定制化项cornerstone.segmentation.loadMultiframeAsPart10> 默认值true。预取被"等待到完成或失败"(刻意不加超时):失败的实例抓取会快速回退到逐帧加载,而慢速的大体积抓取仍是到达全部帧的最快路径。
与多帧相关的 CHANGELOG 记录包括:3.10.0-beta.139 的seg: multiframe SEG(#4890)、3.10.0-beta.11 的multiframe: metadata handling of NM studies and loading order(#4554)、3.10.0-beta.60 的Having sop instance in a per-frame or shared attribute breaks load(#4560,修复 SOP 实例位于 per-frame 或 shared 属性导致加载失败的问题),以及 3.11.0-beta.80 引入的WebGLContextPool for parallel rendering(#5196)与 3.11.0-beta.77 引入的SequentialRenderingEngine(#5195,解决高分辨率显示器上 canvas 尺寸限制与性能退化、增强多显示器支持)——后者虽属于渲染引擎层面,但直接影响 SEG 与 MPR 等多视口场景的渲染稳定性。
颜色处理:CIELab 推荐色与调色板回退
DICOM SEG 标准允许每个分割段携带RecommendedDisplayCIELabValue(推荐显示 CIELab 颜色)。本扩展的加载逻辑(getSopClassHandlerModule.ts)会:
- 对每个分割段取
RecommendedDisplayCIELabValue; - 通过 dicomlabToRGB.ts 将其转换为 RGB 存入
rgba; - 若某段缺失该值,则标记
usedRecommendedDisplayCIELabValue = false,改用CONSTANTS.COLOR_LUT[i % CONSTANTS.COLOR_LUT.length]默认调色板颜色,并弹出 5 秒的警告通知,说明"未找到推荐 CIELab 值,使用了默认颜色"。
与颜色相关的演进修复包括:3.13.0-beta.23 的palette color 8 encoded 16(#5823,修复 8 位调色板被按 16 位编码导致的上色错误)、3.10.0-beta.9 的colorlut: use the correct colorlut index and update vtk(#4544,修正调色板索引并升级 vtk)、3.13.0-beta.11 的colors: Replaces legacy colors with ui-next colors(#5351,以 ui-next 颜色体系替换遗留颜色)、3.12.0-beta.87 的SegmentationStyle: Fix inactive contour visibility and styling(#5563,修复非活动轮廓的可见性与样式)、3.9.0-beta.54(#4181,升级 CS3D 解决超声着色问题)等。
定制化配置:从存储格式到交互行为
本扩展通过 getCustomizationModule.ts 注册了默认定制化项(见 segmentationCustomization.ts):
const segmentationCustomization = { 'segmentation.store.defaultMode': DEFAULT_SEG_STORE_MODE, // 'labelmap' 'segmentation.store.transferSyntaxUID': DEFAULT_SEG_STORE_TRANSFER_SYNTAX_UID, // RLE Lossless (1.2.840.10008.1.2.5) 'segmentation.segmentLabel': { enabledByDefault: false, hoverTimeout: 1, } satisfies SegmentLabelCustomization, };各定制化项的作用域与默认值如下:
| 定制化项 | 类型 | 默认值 | 作用 |
|---|---|---|---|
segmentation.store.defaultMode | 'labelmap' \| 'bitmap' | 'labelmap' | SEG 导出/存储时使用的 SOP Class 模式:labelmap(1.2.840.10008.5.1.4.1.1.66.7)或 bitmap(1.2.840.10008.5.1.4.1.1.66.4) |
segmentation.store.transferSyntaxUID | string | 1.2.840.10008.1.2.5(RLE Lossless) | SEG 导出/存储时使用的传输语法 |
segmentation.segmentLabel | 对象 | 关闭、悬停超时 1s | 段标签工具(segment label tool)的默认行为 |
cornerstone.segmentation.loadMultiframeAsPart10 | boolean | true | 多帧 SEG 是否以单个 Part 10 对象整体预取 |
missingReferenceDisplaySetHandler | function | 无 | 被引用 DisplaySet 缺失时的自定义处理 |
存储优先级:根据 segmentationConfig.ts 的说明,数据源可在configuration.segmentation.store下设置defaultMode与transferSyntaxUID覆盖全局定制化项——因为不同后端支持不同的 SEG 编码方式,数据源级配置优先于应用级定制化默认值。getSegmentationSaveOptions汇总这些规则,供@cornerstonejs/adapters的generateSegmentation在导出/存储 SEG 时使用,默认即Label Map + RLE Lossless;只有在需要位图模式或非压缩 Explicit VR Little Endian 时才需要额外定制。
与定制化相关的演进记录还包括:3.11.0-beta.96 的segmentation: Add customization for handling missing referencedDisplaySetInstanceUID for the SEG/RTSTRUCT(#4983,为 SEG/RTSTRUCT 缺失引用 UID 增加定制化处理)、3.10.0-beta.71 的customization: new customization service api(#4688)、3.10.0-beta.85 的Add customization support for more UI components(#4634),以及 3.12.0-beta.68 的segmentation: Lock all rehydrated segmentation segments when panelSegmentation.disableEditing is true(#5503,当面板配置panelSegmentation.disableEditing为真时锁定所有重新水合的分割段)。
标签图分割与分割工具演进
本扩展在 3.11.0-beta.64(2025-06)随labelmap: Add labelmap segmentation in OHIF(#5158)正式支持 OHIF 内新建 labelmap 分割。围绕分割创建与编辑的能力在 CHANGELOG 中持续增强:
- 3.10.0-beta.144
segmentation: Enhance Segmentation with New AI and Once Click Tools(#4910):新增 AI 与单击式工具; - 3.10.0-beta.131
segmentation: Enhance Segmentation Tools with Preview and Selection Features(#4870):预览与选择功能; - 3.10.0-beta.126
segmentation: segment statistics, labelmap interpolation and segment bidirectional(#4865):段统计、labelmap 插值与分段双向测量; - 3.10.0-beta.129
overlapping segments(#4849):重叠分割段渲染支持; - 3.11.0-beta.75
add segment label tool(#5164)与 3.11.0-beta.113improve segment label(#5217):段标签工具与标签显示优化; - 3.9.0-beta.58(#3632)
segmentation mode: Add create, and export SEG with Brushes:分割模式下用刷子(Brushes)创建并导出 SEG; - 3.9.0-beta.75(#3692)
Segmentation: download RTSS from Labelmap:从 labelmap 下载 RTSS; - 3.9.0-beta.70(#4203)
seg: maintain algorithm name and algorithm type when DICOM seg is exported or downloaded:导出/下载 DICOM SEG 时保留算法名称与算法类型。
工具与交互类修复贯穿多个版本:3.12.0-beta.95 的sculptor tool fixes(#5595)、3.12.0-beta.85 的interpolation: Auto accept interpolation when the interpolation process is completed(#5555,插值完成后自动接受)、3.12.0-beta.81 的SegmentationTools: Changes of brush/eraser radius with hotkey do not reflect on segmentation tool(#5535,修复热键调整笔刷/橡皮半径不生效)、3.10.0-beta.33 的tools: enable additional tools in volume viewport(#4620)等。
渲染稳定性、水合导航与视口状态
SEG 的渲染与水合(hydrated SEG 叠加显示)是涉及视口状态、挂片协议与帧引用准确性的系统性工程,CHANGELOG 中可梳理出以下几条主线:
水合前后导航状态保持:3.9.0-beta.34hydration: Maintain the same slice that the user was on pre hydration in post hydration for SR and SEG(#4200);3.10.0-beta.145Pass the correct sop uid + frame for rehydration to prevent associating rehydrated measurements with the wrong data(#5506);3.12.0-beta.133jump-to-label-map: Use undefined for viewportId for arrow navigation(#5774)。
水合后切片定位:3.10.0-beta.23seg: jump to the first slice in SEG and RT that has data(#4605,跳到 SEG/RT 首个含数据切片)、3.10.0-beta.152segmentation: Add segment jump for new segments and make panels scrollable(#4928,新分割段跳转与面板滚动)。
未水合 SEG 的跨挂片协议可见性:3.11.0-beta.67segmentation: Changes to fix problems with non hydrated/loaded segmentations to be viewable when switching hanging protocols (e.g. MPR)(#5139);3.13.0-beta.49segmentation: restrict overlay segmentation menu to same frame of reference as viewport background display set(#5900,将叠加分割菜单限制在视口背景 DisplaySet 同一帧参考系内);3.12.0-beta.110prevent annotation from appearing in active viewport when switching series with different Frame of Reference UID(#5630)。
视口状态重置与布局切换:3.9.0-beta.85segmentation creation and segmentation mode viewport rendering(#4193)、3.9.0-beta.92segmentation: Address issue where segmentation creation failed on layout change(#4153,修复布局切换时分割创建失败)、3.12.0-beta.773DSegmentation: The viewports become blank when loading the seg file in advanced layout after closing the seg file from any other advanced layout(#5505)、3.9.0-beta.121viewport: Reset viewport state and fix CINE looping, thumbnail resolution, and dynamic tool settings(#4037)、3.9.0-beta.128resize: Optimize resizing process and maintain zoom level(#3889)。
与 TMTV 的协同:3.12.0-beta.128TMTV: Consider blend mode when adding segmentation representations(#5735)、3.9.0-beta.108tmtv-mode: Add Brush tools and move SUV peak calculation to web worker(#4053)、3.9.0-beta.60(#3988)segmentation: Enhanced segmentation panel design for TMTV(TMTV 专用分割面板设计)。
3D 表现:3.12.0-beta.122segmentation: List surface representations in the segmentation table for 3D views(#5700,在 3D 视图分割表中列出 surface 表现)、3.9.0-beta.76(#4762)core: Address 3D reconstruction and Android compatibility issues(3D 重建与 Android 兼容性)、3.9.0-beta.54(#4008)new layout: address black screen bugs。
帧引用与元数据准确性:3.12.0-beta.69(#5506)与 3.13.0-beta.53rename DisplaySet.frameOfReferenceUID back to FrameOfReferenceUID(#5943,保留框架参考系 UID 字段命名一致性)。
测试与质量保障
仓库在 tests 目录下提供了覆盖该扩展主要行为的 Playwright 端到端测试,与 CHANGELOG 中的功能记录相互印证,例如:
- SEGHydration.spec.ts:验证 SEG 水合后叠加渲染、删除与重载;
- SEGNoHydrationThenMPR.spec.ts 与 SEGHydrationThenMPR.spec.ts:验证未水合/水合 SEG 切换到 MPR 挂片协议后的可见性(对应 #5139 修复);
- SEGHydrationFromMPR.spec.ts、SEGHydrationFrom3DFourUp.spec.ts:从 MPR / 3D 布局触发水合;
- OverlappingSegmentationRendering.spec.ts:重叠分割段渲染(对应 #4849);
- SegmentationPanel.spec.ts 与 SegmentationSeriesNavigation.spec.ts:分割面板与系列导航;
- LabelMapSegLocking.spec.ts、LabelMapSegmentationColorChange.spec.ts:labelmap 锁定与颜色修改。
此外,测试辅助工具 visitStudyAndHydrate.ts 封装了"访问研究并水合"的公共流程,供多个 SEG/RT/SR 测试复用。
底层依赖的持续升级
CHANGELOG 显示该扩展的稳定性高度依赖 Cornerstone3D 生态的演进,频繁出现"update cs3d / cornerstone dependencies"类条目,例如:3.13.0-beta.89(#6043,测试适配 Cornerstone3D 5.0)、3.13.0-beta.25(#5837,CS3D 4.18.2)、3.12.0-beta.121(#5701,修复截图后分割异常)、3.12.0-beta.111(#5664,修复分割段可见性)、3.12.0-beta.59(#5494,依赖精确版本锁定以提升供应链安全)、3.10.0-beta.114(#4816,Cornerstone3D 3.0 适配)、3.9.0-beta.72(#3892)、3.9.0-beta.73(#3885)、3.9.0-beta.64(#3806,新增 HTJ2K TSUIDS 支持)等。可见 SEG 渲染的正确性、性能与安全性高度依赖底层渲染内核与适配器版本的匹配。
版本演进时间线速览
结合 CHANGELOG 中的版本节点(以版本号为纵轴),可梳理出该扩展近年来的能力里程碑:
| 时间 | 版本节点 | 代表性能力 |
|---|---|---|
| 2024-06 | 3.9.0-beta.58 | 分割模式创建并导出 SEG(Brushes) |
| 2024-07 | 3.9.0-beta.72~75 | CS3D 升级修复分割 bug、labelmap 下载 RTSS |
| 2024-09 | 3.9.0-beta.90 起 | 4D 动态体积渲染、新布局选择器(含 3D 体积渲染) |
| 2025-03 | 3.10.0-beta.126~144 | 段统计、labelmap 插值、重叠分割段、AI 与单击式工具、多帧 SEG 修复 |
| 2025-06 | 3.11.0-beta.64 | OHIF 内 labelmap 分割 |
| 2025-07 | 3.11.0-beta.80 | WebGLContextPool 并行渲染、SequentialRenderingEngine |
| 2025-10~12 | 3.12.0-beta.68~122 | 水合段锁定、分割表 surface 表现、视图防崩溃守卫 |
| 2026-02~04 | 3.13.0-beta.11~53 | ui-next 颜色、palette 8/16 修复、叠加分割菜单同帧参考系限制 |
| 2026-06 | 3.13.0-beta.89 | 适配 Cornerstone3D 5.0 测试链 |
需要说明的是:CHANGELOG 中约三分之二的版本节点属于 "Version bump only"(仅版本号提升、无独立变更),上述时间线仅摘录包含实际 Features / Bug Fixes 的节点,反映该扩展真实的能力演进。
小结:如何在 OHIF 中落地 SEG 工作流
综合 README、源码与 CHANGELOG,在 OHIF 中使用 DICOM SEG 的完整工作流可归纳为:
- 识别与建组:SopClassHandler 依据两个 SEG SOP Class UID 将系列转成派生 DisplaySet,并关联被引用系列(同一帧参考系);
- 加载与解析:点击 SEG 视口操作栏的 SEG Pill(或由模式/挂片协议触发
load),经createFromDicomSegImageId解析为 labelmap/bitmap 分割,颜色遵循RecommendedDisplayCIELabValue并以 COLOR_LUT 兜底; - 水合与叠加:SEG 加载完成后可水合,叠加渲染到同一帧参考系的所有视口;水合前后保持用户所在切片位置;
- 定制化:通过
segmentation.store.*、cornerstone.segmentation.loadMultiframeAsPart10、missingReferenceDisplaySetHandler、panelSegmentation.disableEditing等定制化项调整存储格式、预取策略与交互行为; - 验证:参照 tests 下的 SEGHydration、SEGNoHydrationThenMPR、OverlappingSegmentationRendering 等端到端用例回归验证。
如需深入实现细节,可继续阅读 getSopClassHandlerModule.ts(加载调用链)、OHIFCornerstoneSEGViewport.tsx(视口与水合)、segmentationConfig.ts(解析器与存储配置)以及完整的 CHANGELOG.md。
【免费下载链接】ViewersOHIF zero-footprint DICOM viewer and oncology specific Lesion Tracker, plus shared extension packages项目地址: https://gitcode.com/GitHub_Trending/vi/Viewers
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考