零部署打开一整套 PET-CT 检查:OHIF 零足迹 DICOM 查看器实现笔记 零部署打开一整套 PET-CT 检查OHIF 零足迹 DICOM 查看器实现笔记【免费下载链接】ViewersOHIF zero-footprint DICOM viewer and oncology specific Lesion Tracker, plus shared extension packages项目地址: https://gitcode.com/GitHub_Trending/vi/Viewers放射科医生点开一个 DICOM Web 链接几秒后屏幕出现配准好的 PET-CT轴位、代谢图、融合三层同步联动——这是零足迹 DICOM 查看器 OHIF 在浏览器里做的事。它面向医院和科研机构不装客户端影像直接跑在浏览器里功能按扩展组织、按需组合。零足迹 DICOM 查看器的骨架mode 声明布局extension 提供能力仓库是一个 pnpm monorepoplatform/core/ 是宿主extensions/ 是能力包modes/ 是可直接用的组合。宿主定义的 Extension 接口非常克制preRegistration、onModeEnter/onModeExit两个生命周期钩子加一组getXxxModule——viewport、panel、toolbar、commands、customization、sopClassHandler、hangingProtocol各扩展按需填。我注意到一个有意思的取舍mode 并不直接 import 扩展而是声明一张依赖表。modes/basic/src/index.tsx 里写着extensionDependencies: { ohif/extension-cornerstone: ^3.0.0, ... }——语义上等价于 peerDependencies插件与宿主约定最低版本实际解析交给宿主。同文件里 sopClassHandlers 列表的顺序也有讲究video handler 刻意排在图像 handler 之前注释直接解释了原因先剥离 video 传输语法再让通用 handler 接手。组合的威力在 modes/longitudinal/ 更明显它不重写布局只继承 basic 的 layout然后把视口和侧栏换成被追踪版本。宿主出服务容器和事件总线扩展出能力mode 决定长什么样——三层分工到此清晰。骨架搭好之后先看一帧数据怎么穿过这套骨架。浏览器医学影像的一帧数据链路从 DICOM Web 响应到上屏一帧 CT 的上屏路径分四段每段都有明确归属。第一段取数extensions/default/ 里的 DicomWebDataSource 负责与影像归档走 QIDO/WADO-RS也支持多源合并和本地文件。第二段归组系列元数据交给 sopClassHandler 按 SOP Class 拆成 display set——stack、SR、PDF、video 各有各的 handler这是整个查看器什么都能看的调度点。第三段加载display set 里每帧的 imageId 携带了数据源信息而加载器是按名字注册的——registerVolumeLoader( cornerstoneStreamingImageVolume, cornerstoneStreamingImageVolumeLoader );见 initWADOImageLoader.js注册了两个流式 volume loader实际取帧和解码委托给cornerstonejs/dicom-image-loader编解码走对应 WASM codec。值得说的是扩展把四个 codec 都钉在 peerDependencies 里而非自身依赖——解码能力被当成基础设施契约而不是扩展细节。CornerstoneCacheService 也挂在这条链上把 cornerstone 内部图像缓存的占用与剩余空间暴露给 UI让内存还剩多少变得可见。单帧走通后下一个问题是多个视口怎么不打架。MPR 三个切面和 3D 体怎么保持同步上面是文档里的演示截图左侧轴、冠、矢三个切面与右上 3D VR 共享同一个体积十字光标随滚动联动。同步的实现比想象中少。frameViewSynchronizer 订阅 STACK_VIEWPORT_SCROLL 与 CAMERA_MODIFIED 事件任一视口滚动时其余按目标 slice 源 slice 索引差跟随——即各平面保持固定片差而非绝对对齐。这个选择让多时间点比较不同检查的对应层号往往不一致比硬对齐好处理得多。3D 一侧依赖 vtk.jscornerstone 扩展的依赖里有kitware/vtk.js 36.4.1。体积不是一次性下载完成的onModeEnter里为 volume 注册了交错渐进式取帧interleaved retrieve stages源码注释原话是先复现一个低分辨率深度体积重建再逐步提精。用户看到的是体素质量一点点涨上来而不是一片黑等 loading。同步只是表面底下的瓶颈是数据量本身。把 GB 级数据驯进浏览器WASM 编解码、Worker 池与流式加载瓶颈在解码全脑 CT 的压缩数据动辄上百 MB。OHIF 不自己写解码器peerDependencies 里的四个 WASM codeccodec-openjpeg、codec-openjph、codec-libjpeg-turbo-8bit、codec-charls分别覆盖 JPEG 2000、JPEG-LS、RLE 等医学压缩格式解码全部丢进 Web Worker 池。池子的规模决策值得一读同样在 initWADOImageLoader.jsmaxWebWorkers: Math.min( Math.max(navigator.hardwareConcurrency - 1, 1), appConfig.maxNumberOfWebWorkers )CPU 核数减一、最少留一个再受应用配置封顶——主线程永远不被解码占满。取数侧默认流式stack 的默认选项是streaming: true, decodeLevel: 1即取一帧解一帧而不是整系列下载完再动。内存回收也有明确边界onModeExit会清空图像加载/取帧队列和 Part10 元数据缓存源码注释写明目的是防止模式切换时的内存泄漏。数据层之外最见功力的是垂直场景的处理细节。放疗规划叠加层一个 RTSTRUCT 的轮廓点从哪来这是演示截图GTV、PTV、Brain Stem 等十几个器官轮廓以不同颜色叠在头部 CT 上。背后的工作量集中在 extensions/cornerstone-dicom-rt/ 的 loadRTStruct.js轮廓点要兼容三种存储形态——直接数组、InlineBinary base64以及 DICOM Web 场景最常见的 BulkDataURI轮廓点不在文件里要回到归档的 bulkdata 端点再取一次。颜色也有两个来源直接的 ROIDisplayColor或把 CIELab 推荐值用 dcmjs 的 dicomlab2RGB 转成 RGB。这类细节正是能显示和显示得对的分界线。放疗处理的是结构叠加肿瘤随访要处理的则是状态一致性。病灶追踪临时测量和永久状态之间的一致性modes/longitudinal/ 模式服务于肿瘤疗效评估核心是一台状态机画完标注后弹出是否追踪的提示。答是——实线进入右侧测量面板可导出 DICOM SR答否——虚线只留在图像上不可导出。这张流程图来自该模式的 README真正的复杂度藏在 SR 导入时重新载入结构化报告前先判断该序列是否已在追踪。是——SR 只以只读方式呈现用户还能调窗宽窗位、画临时测量视口左上角挂锁形图标否——历史测量被重新水合进视口全部标记为已追踪。这一个判断避免了用户新测量和历史报告两个数据源互相覆盖。旁边的 modes/tmtv/ 模式是同一套思路的延伸PET-CT 融合上加阈值分割标出代谢活跃病灶右侧面板直接给出单灶 SUV 峰值截图为 25.70、体积与 TMTV 总量 85.93 mL可一键导出 CSV 或 RT 报告。功能看完回到工程现状。它现在跑得怎么样beta 线上的双引擎迁移与 Playwright 回归基线说实话根 package 版本是 3.14.0-beta.56master 就是 beta 线。代码里正进行一项迁移——新一代 next 视口PLANAR_NEXT与旧引擎并行注释反复强调 flag 关闭时旧路径保持字节级一致等于把旧实现钉成回归基线。测试侧tests/ 目录有 80 余个 Playwright spec覆盖 MPR、SEG 水合、RT 叠加、TMTV 等场景screenshots/下是成套的截图回归库对影像项目来说这种视觉基线相当扎实。边界也明确零足迹意味着解码与渲染全在浏览器侧完成超大量 4D 序列、全切片影像的吞吐直接受网络与 WASM 解码速度制约帧率上限与其他浏览器渲染方案没有本质区别。判断它把 PACS 级能力拆成宿主、扩展、模式三层再拼回浏览器测试基线说明成熟度不低。想评估 DICOM Web 方案可直接跑仓库的 demo 构建连 Orthanc 数据源验证实际链路。【免费下载链接】ViewersOHIF zero-footprint DICOM viewer and oncology specific Lesion Tracker, plus shared extension packages项目地址: https://gitcode.com/GitHub_Trending/vi/Viewers创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考