新闻详情

新闻详情

首页 / 资讯中心 / 详情

OHIF 3.10 到 3.11 命令迁移指南:SR 水合与位置展示命令的完整改造

发布时间:2026/9/18 18:09:10来源:尧图网络
OHIF 3.10 到 3.11 命令迁移指南:SR 水合与位置展示命令的完整改造
OHIF 3.10 到 3.11 命令迁移指南SR 水合与位置展示命令的完整改造【免费下载链接】ViewersOHIF zero-footprint DICOM viewer and oncology specific Lesion Tracker, plus shared extension packages项目地址: https://gitcode.com/GitHub_Trending/vi/Viewers本文是 OHIF 零足迹 DICOM 查看器从 3.10 升级到 3.11 的迁移指南核心章节聚焦于命令Commands层面的破坏性变更loadSRMeasurements命令被移除、SR 测量加载职责转移给hydrateSecondaryDisplaySet以及updateStoredPositionPresentation参数从单值改为数组。读者将掌握新命令的完整调用链、displaySet对象的获取方式、viewport 定位策略以及如何处理与之配套的 UIModalityLoadBadge与TrackedMeasurementsContext变化从而平滑迁移自定义扩展代码。迁移概览三个必须处理的命令变更OHIF 3.11 对命令系统做了一次职责收敛式的重构把原本分散在各扩展中的衍生显示集derived display set水合逻辑集中到核心 Cornerstone 扩展中。本次迁移涉及三个核心点命令3.10 状态3.11 状态loadSRMeasurements存在于ohif/extension-cornerstone-dicom-sr负责水合 SR 并直接更新视口已移除由hydrateSecondaryDisplaySet替代hydrateStructuredReport水合 SR 并操作视口仅负责水合 SR 并返回数据不再直接操作视口updateStoredPositionPresentation参数为displaySetInstanceUID单个值参数改为displaySetInstanceUIDs数组迁移的整体目标将 SR、SEG、RTSTRUCT 这类二级显示集的水合hydration与视口更新逻辑统一收敛到ohif/extension-cornerstone的hydrateSecondaryDisplaySet命令中同时让 UI 层通过统一的交互入口ModalityLoadBadge、TrackedMeasurementsContext触发水合。updateStoredPositionPresentation参数改为数组第一处破坏性变更出现在位置展示position presentation存储命令上现在使用displaySetInstanceUIDs代替displaySetInstanceUID作为参数。在 3.11 源码中该命令的实现在 extensions/cornerstone/src/commandsModule.ts#L623-L686签名如下updateStoredPositionPresentation: ({ viewportId, displaySetInstanceUIDs, // 由原来的 displaySetInstanceUID 改为数组 referencedImageId, options, }) { const presentations cornerstoneViewportService.getPresentations(viewportId); const { positionPresentationStore, setPositionPresentation, getPositionPresentationId } usePositionPresentationStore.getState(); // ... }从实现可以看到displaySetInstanceUIDs现在被要求是非空数组源码中显式判断Array.isArray(displaySetInstanceUIDs) displaySetInstanceUIDs.length 0用于在positionPresentationStore中查找与所有 UID 均匹配的既有键值从而复用或创建位置展示记录。这种设计源于 3.11 中水合可以在视口尚未创建时执行见下文hydrateSecondaryDisplaySet的storePositionPresentation逻辑单个 UID 已不足以描述被引用系列的完整位置上下文。典型的调用示例来自jumpToMeasurementViewport命令commandsModule.ts#L298-L305commandsManager.run(updateStoredPositionPresentation, { viewportId: viewportToUpdate.viewportId, displaySetInstanceUIDs: [referencedDisplaySetInstanceUID], referencedImageId: measurement.referencedImageId, options: { ...measurement.metadata, }, });如果你在自定义代码中调用了该命令迁移时只需将原来传入的单个displaySetInstanceUID: uid改为displaySetInstanceUIDs: [uid]。loadSRMeasurements被移除改用hydrateSecondaryDisplaySet变更背景在 OHIF 3.10 中loadSRMeasurements命令原属于ohif/extension-cornerstone-dicom-sr承担了两个职责水合结构化报告Structured ReportSR解析 SR 中的测量数据与被引用系列 UID操作视口把被引用的图像系列显示到视口中。这种一个命令既解析又渲染的设计在 3.11 中被拆解与重新定位hydrateStructuredReport命令仍来自ohif/extension-cornerstone-dicom-sr只做水合解析 SR 并返回数据含SeriesInstanceUIDs不再直接操作视口。其底层实现见 extensions/cornerstone-dicom-sr/src/utils/hydrateStructuredReport.ts核心流程包括通过MeasurementReport.generateToolState解析 SR 测量、利用measurementService.getSourceMappings过滤出支持测量的注解类型、区分 2DSCOORD与 3DSCOORD3D的引用数据解析并返回{ StudyInstanceUID, SeriesInstanceUIDs }新的hydrateSecondaryDisplaySet命令位于ohif/extension-cornerstone集中处理 SR/SEG/RTSTRUCT 等二级显示集的水合与视口更新。迁移步骤官方迁移指南给出了三步走第 1 步定位旧命令调用点在代码中搜索commandsManager.runCommand(loadSRMeasurements, ...)的所有调用位置。第 2 步替换为hydrateSecondaryDisplaySet调用新命令时需要传入完整的displaySet对象而非 UID和目标viewportId。迁移后的代码结构如下来自官方文档示例const { displaySetService, viewportGridService } servicesManager.services; // 1. 通过 UID 获取 SR displaySet 对象 const srDisplaySet displaySetService.getDisplaySetByUID(srDisplaySetInstanceUID); // 2. 确定目标 viewportId例如活动视口 const viewportId viewportGridService.getActiveViewportId(); // 或指定具体的 viewportId if (srDisplaySet viewportId) { commandsManager.runCommand(hydrateSecondaryDisplaySet, { displaySet: srDisplaySet, viewportId: viewportId, }); } else { console.warn(SR DisplaySet or ViewportId not found, cannot hydrate.); }对应的 diff 形式- // Old way: using loadSRMeasurements - commandsManager.runCommand(loadSRMeasurements, { - displaySetInstanceUID: srDisplaySetInstanceUID, - // viewportId was implicitly the active one or not directly specifiable here - }); - // New way: using hydrateSecondaryDisplaySet const { displaySetService, viewportGridService } servicesManager.services; const srDisplaySet displaySetService.getDisplaySetByUID(srDisplaySetInstanceUID); const viewportId viewportGridService.getActiveViewportId(); if (srDisplaySet viewportId) { commandsManager.runCommand(hydrateSecondaryDisplaySet, { displaySet: srDisplaySet, viewportId: viewportId, }); }第 3 步为 UI 层改造做适配见下文UI 变更小节。新命令的底层调用链从 3.11 源码 extensions/cornerstone/src/commandsModule.ts#L343-L441 可以看到hydrateSecondaryDisplaySet的完整实现官方文档所述的三步内部流程在这里得到一一印证hydrateSecondaryDisplaySet: async ({ displaySet, viewportId }) { if (!displaySet) { return; } const viewport cornerstoneViewportService.getCornerstoneViewport(viewportId); if (displaySet.isOverlayDisplaySet) { // 对 SEG/RTSTRUCT记录分割展示表示类型 Contour/Surface/Labelmap commandsManager.runCommand(updateStoredSegmentationPresentation, { displaySet, type: segmentationType, }); } // 标记为已水合——即使视口尚未创建水合决策也在此完成 displaySet.isHydrated true; const referencedDisplaySetInstanceUID displaySet.referencedDisplaySetInstanceUID; const storePositionPresentation refDisplaySet { // 将被引用系列的位置展示与当前 viewportId 关联 commandsManager.runCommand(updateStoredPositionPresentation, { viewportId, displaySetInstanceUIDs: [refDisplaySet.displaySetInstanceUID], }); }; if (displaySet.Modality SEG || displaySet.Modality RTSTRUCT) { // 分支一加载分割显示集到视口 const referencedDisplaySet displaySetService.getDisplaySetByUID(referencedDisplaySetInstanceUID); storePositionPresentation(referencedDisplaySet); const results commandsManager.runCommand(loadSegmentationDisplaySetsForViewport, { viewportId, displaySetInstanceUIDs: [referencedDisplaySet.displaySetInstanceUID], derivedDisplaySetInstanceUID: displaySet.displaySetInstanceUID, viewportType: getHydrationViewportTypeForModality(displaySet.Modality), }); return results; } else if (displaySet.Modality SR) { // 分支二水合 SR自动找到被引用图像显示集并更新视口 const results commandsManager.runCommand(hydrateStructuredReport, { displaySetInstanceUID: displaySet.displaySetInstanceUID, }); const { SeriesInstanceUIDs } results; const referencedDisplaySets displaySetService.getDisplaySetsForSeries(SeriesInstanceUIDs[0]); referencedDisplaySets.forEach(storePositionPresentation); if (referencedDisplaySets.length) { actions.setDisplaySetsForViewports({ viewportsToUpdate: [ { viewportId: viewportGridService.getActiveViewportId(), displaySetInstanceUIDs: [referencedDisplaySets[0].displaySetInstanceUID], }, ], }); } return results; } },对照官方文档的Explanation部分调用hydrateSecondaryDisplaySet传入 SR 的displaySetdisplaySet.Modality SR时内部先调用hydrateStructuredReport命令解析 SR获得被引用图像的SeriesInstanceUIDs再通过displaySetService.getDisplaySetsForSeries(SeriesInstanceUIDs[0])自动找到对应的图像显示集最后通过setDisplaySetsForViewports更新指定的视口源码中取活动视口viewportGridService.getActiveViewportId()来显示主被引用图像系列。此外实现中有两个值得注意的细节水合与视口解耦displaySet.isHydrated true在水合开始时即被设置注释明确说明isHydrated means display this display set as part of a standard view. That is decided here and does not depend on a viewport existing yet.这意味着 3.11 中水合可以发生在目标视口创建之前位置展示通过updateStoredPositionPresentation预先记录视口挂载后自动恢复这正是前文参数改为数组的深层原因分支统一SEG/RTSTRUCT 走loadSegmentationDisplaySetsForViewportSR 走hydrateStructuredReportsetDisplaySetsForViewports所有衍生显示集的水合逻辑集中在一处。RT 水合的协同改造作为佐证ohif/extension-cornerstone-dicom-rt中的 RTSTRUCT 水合也改用了新命令。根据官方迁移文档 hydration.mdpromptHydrateRT不再自带大段 Promise 与对话框逻辑而是复用ohif/extension-cornerstone的通用工具utils.promptHydrationDialogfunction promptHydrateRT({ servicesManager, rtDisplaySet, viewportId, preHydrateCallbacks, hydrateRTDisplaySet, }: { servicesManager: AppTypes.ServicesManager; rtDisplaySet: AppTypes.DisplaySet; viewportId: string; preHydrateCallbacks?: Types.HydrationCallback[]; hydrateRTDisplaySet: Types.HydrationCallback; }) { return utils.promptHydrationDialog({ servicesManager, viewportId, displaySet: rtDisplaySet, preHydrateCallbacks, hydrateCallback: hydrateRTDisplaySet, type: RTSTRUCT, }); }而传入的hydrateRTDisplaySet回调在 extensions/cornerstone-dicom-rt/src/viewports/OHIFCornerstoneRTViewport.tsx 中正是调用新命令hydrateRTDisplaySet: async () { return commandsManager.runCommand(hydrateSecondaryDisplaySet, { displaySet: rtDisplaySet, viewportId, }); },通用工具promptHydrationDialog的实现位于 extensions/cornerstone/src/utils/promptHydrationDialog.ts并有配套测试 promptHydrationDialog.test.ts 覆盖其交互流程。SEG 的水合路径同理见 extensions/cornerstone-dicom-seg/src/viewports/OHIFCornerstoneSEGViewport.tsx。UI/按钮层面的变化谁在触发水合官方文档特别提醒与Load SR相关的 UI 按钮也已重构。3.11 中 SR 的水合触发方式有两类TrackedMeasurementsContext当启用ohif/extension-measurement-tracking时测量追踪的上下文会基于状态机measurementTrackingMachine.js中HYDRATE_SR事件触发水合。相关实现位于 extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/TrackedMeasurementsContext.tsx、hydrateStructuredReport.tsx 与 promptHydrateStructuredReport.ts。其中promptHydrateStructuredReport内部即调用commandsManager.runCommand(hydrateSecondaryDisplaySet, ...)。ModalityLoadBadge组件这是 3.11 新增的视口角标组件出现在包含 SR、SEG、RTSTRUCT 显示集的视口中提供 LOAD 操作按钮来触发hydrateSecondaryDisplaySet。其实现位于 extensions/cornerstone/src/components/ModalityLoadBadge/ModalityLoadBadge.tsx关键逻辑{statusInfo.type ! SR ( ViewportActionButton onInteraction{() { commandsManager.runCommand(hydrateSecondaryDisplaySet, { displaySet: statusInfo.displaySet, viewportId, }); }} {loadStr} /ViewportActionButton )}值得注意该组件对 SR 类型不显示 LOAD 按钮源码注释说明 SR 的水合由测量追踪上下文通过状态机处理这并非回归而 SEG/RTSTRUCT 的 LOAD 按钮则直接调用hydrateSecondaryDisplaySet。组件还会根据isHydrated、isRehydratable、isLocked等状态展示不同的图标与 tooltip 提示。如果你在 3.10 中有自定义 UI 调用loadSRMeasurements需要按上文说明适配为调用hydrateSecondaryDisplaySet如果你的自定义 UI 未使用测量追踪扩展则需自行处理 SR 的 LOAD 入口。常见迁移问题与核对清单问题 1调用hydrateSecondaryDisplaySet时拿不到srDisplaySet确保传入的是displaySetService.getDisplaySetByUID(uid)返回的完整对象而不是 UID 字符串本身。命令内部依赖displaySet.Modality、displaySet.referencedDisplaySetInstanceUID、displaySet.isOverlayDisplaySet等字段做分支判断。问题 2视口没有更新确认viewportId有效。官方示例使用viewportGridService.getActiveViewportId()获取活动视口如需指定其他视口务必传入已存在于cornerstoneViewportService中的视口 ID。问题 3SR 不兼容不可再水合ModalityLoadBadge中isRehydratable为false时tooltip 会显示 This structured report is not compatible with this application.。这类 SR 无法通过新命令水合需要检查 SR 是否包含受支持的测量类型取决于measurementService.getSourceMappings中注册的映射。迁移核对清单全局搜索loadSRMeasurements确认无残留调用将updateStoredPositionPresentation调用中的displaySetInstanceUID改为数组形式的displaySetInstanceUIDs所有 SR 加载逻辑改为先获取displaySet对象、再调用hydrateSecondaryDisplaySet({ displaySet, viewportId })自定义 UI 中的 Load SR 按钮改接新命令或委托给TrackedMeasurementsContext/ModalityLoadBadge若直接使用hydrateStructuredReport确认其返回值{ StudyInstanceUID, SeriesInstanceUIDs }被正确消费视口更新已不在该命令职责内。参考资料迁移指南总览platform/docs/docs/migration-guide/3p10-to-3p11/index.md命令迁移本文主体platform/docs/docs/migration-guide/3p10-to-3p11/commands.md水合系统迁移含promptHydrateRT改造示例platform/docs/docs/migration-guide/3p10-to-3p11/hydration.md新版命令实现extensions/cornerstone/src/commandsModule.tsSR 水合命令与底层解析extensions/cornerstone-dicom-sr/src/commandsModule.ts、extensions/cornerstone-dicom-sr/src/utils/hydrateStructuredReport.ts通用水合对话框工具及测试extensions/cornerstone/src/utils/promptHydrationDialog.ts、promptHydrationDialog.test.ts视口角标组件extensions/cornerstone/src/components/ModalityLoadBadge/ModalityLoadBadge.tsx测量追踪上下文水合extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/【免费下载链接】ViewersOHIF zero-footprint DICOM viewer and oncology specific Lesion Tracker, plus shared extension packages项目地址: https://gitcode.com/GitHub_Trending/vi/Viewers创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

用 garak LLM 漏洞扫描器检测你的模型会不会被越狱 2026/9/18 18:42:21

用 garak LLM 漏洞扫描器检测你的模型会不会被越狱

用 garak LLM 漏洞扫描器检测你的模型会不会被越狱 【免费下载链接】garak the LLM vulnerability scanner 项目地址: https://gitcode.com/GitHub_Trending/ga/garak 你的客服 AI 突然把内部系统提示词原样吐给了用户,这就是提示注入越狱现场。garak 是一个…

阅读更多 →
Vue+Spring Boot宠物领养平台架构设计与优化 2026/9/18 18:42:20

Vue+Spring Boot宠物领养平台架构设计与优化

简介:本资源是一份面向计算机专业本科生的Java毕业设计论文,聚焦VueSpringBoot技术栈构建的宠物领养救助平台,解决流浪动物信息不对称、领养流程低效等社会实际问题,适用于课程设计、毕设参考及全栈开发初学者实践。文档为单个4.6…

阅读更多 →
Flutter与鸿蒙深度结合:沉浸式阅读APP开发实践 2026/9/18 18:42:20

Flutter与鸿蒙深度结合:沉浸式阅读APP开发实践

1. 项目背景与核心价值作为一名长期从事移动端开发的工程师,我最近在探索如何将Flutter框架与鸿蒙系统深度结合。传统跨平台方案在鸿蒙生态中往往存在性能损耗和原生特性支持不足的问题,而这次要开发的沉浸式小说阅读APP恰好是个绝佳的技术验证场景。小说…

阅读更多 →
Redux Reducer 逻辑拆分:函数式分解与 Reducer 组合的术语体系与实战模式 2026/9/18 18:42:20

Redux Reducer 逻辑拆分:函数式分解与 Reducer 组合的术语体系与实战模式

Redux Reducer 逻辑拆分:函数式分解与 Reducer 组合的术语体系与实战模式 【免费下载链接】redux A JS library for predictable global state management 项目地址: https://gitcode.com/gh_mirrors/re/redux 对于任何有一定规模的应用程序,把全…

阅读更多 →
低功耗段码LCD驱动芯片TM16C21:原理、设计与实战排坑 2026/9/18 18:42:20

低功耗段码LCD驱动芯片TM16C21:原理、设计与实战排坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
cnfast性能优化原理:Tailwind类名拼接的构建时加速 2026/9/18 18:39:20

cnfast性能优化原理:Tailwind类名拼接的构建时加速

1. 项目概述:一次被严重误读的性能对比,背后是 React 开发者最常踩的认知陷阱“cnfast 与 cn():React 中的 7 倍加速是真的吗?”——这个标题在前端社区刷屏时,我正蹲在公司茶水间调试一个卡顿严…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞