简介:这是一份面向医疗信息化开发者、影像科工程师及医学影像相关专业学习者的DICOM查看器资源,核心为Weasis——一款免费开源的医疗影像浏览工具,可作桌面应用或基于Web的应用使用,适用于医院、健康网络、多中心研究试验及患者医疗场景。资源包为zip格式,整体约2.54MB,当前文件总数与类型明细上游暂未提供,故不展开说明。内容围绕Weasis的构建与集成展开,涵盖master分支(Weasis 3.xx,需Java 8+)与2.5.x、2.0.x、1.2.x等旧分支的版本说明,并涉及灵活集成至HIS或PHR、桌面发行版(Windows、Mac OS X、Linux)、weasis协议Web访问、便携式媒体嵌入式查看器、多国语言支持、服务端与客户端首选项配置、自定义插件API,以及DICOM发送(storeSCU、STOW-RS)、查询检索(C-GET、C-MOVE、WADO-URI)与DICOMWeb、Dicomizer模块等能力。已有1089人浏览学习,适合希望快速了解Weasis架构、集成方式与DICOM通信功能的读者参考。
1. 从一次阅片卡顿说起:Weasis 到底解决什么问题
很多做医疗影像软件的同行都遇到过这个场景:科室里几台老工作站,装的是某款体积庞大的 DICOM 客户端,启动要等半分钟,打开一个几百 MB 的增强 CT 序列就转圈,想换个浏览器看还得重新装一套。更麻烦的是,同一份影像,桌面端能看,Web 端打不开,维护两套代码的团队天天在填坑。Weasis 这个项目就是冲着这类问题去的——它是一个 DICOM 查看器,既能当桌面应用跑,也能以基于 Web 的应用形态部署,一套核心逻辑覆盖两种交付方式。
它的定位不是 PACS 服务器,也不是影像后处理工作站,而是「查看器」这一层:负责把符合 DICOM 标准的影像拉过来、解码、渲染、做基础测量和布局。适合谁?一是需要给现有系统快速补一个阅片入口的集成开发者;二是想自建轻量阅片工具、又不想从零写 DICOM 解析的团队;三是教学或科研场景里,需要批量打开本地影像做标注和导出的个人。理解它的边界很重要:它不替你存影像,也不替你管权限,这些得靠外围系统配合。
2. Weasis 的两种形态:桌面端与 Web 端怎么选、怎么跑
Weasis 最容易被误解的一点,是以为桌面版和 Web 版是两套东西。实际上它们共享同一套影像处理内核,差别主要在启动方式、资源加载路径和与外部系统的对接方式上。选型时先想清楚三件事:影像从哪来、用户在哪台机器上、你能不能控制运行环境。
2.1 桌面形态:本地启动与命令行参数
桌面形态适合影像已经在本地或能通过标准协议拉取的场景。常见做法是通过命令行传入影像地址或配置文件,让它启动后直接加载。下面是一个典型的启动脚本片段,用参数指定要打开的影像来源:
# 启动 Weasis 桌面端并加载指定影像 # -D 开头的参数用于覆盖默认配置,这里指定影像来源和缓存目录 java -Xmx2g \ -Dweasis.cacheDir=/data/weasis-cache \ -Dweasis.profile=viewer \ -jar weasis-launcher.jar \ "dicom:get?studyUID=1.2.840.xxxxx"这段命令里,-Xmx2g控制 JVM 堆上限,影像序列大时这个值要往上调,否则解码阶段容易 OOM;weasis.cacheDir决定本地缓存落在哪,放在机械盘上会明显拖慢二次打开速度;最后的dicom:get是它支持的资源定位写法,用 studyUID 去拉取整个检查。参数说明:weasis.profile用来切换不同的功能配置集,比如只读阅片和带测量工具的阅片可以分成两个 profile,避免给普通用户暴露过多按钮。
2.2 Web 形态:部署方式与浏览器侧加载
Web 形态的核心思路是把查看器作为前端资源部署,影像通过后端接口按需传输。它通常以一个可嵌入的页面或组件形式存在,浏览器负责渲染,服务端负责把 DICOM 转成适合网络传输的格式。部署时要注意两点:一是静态资源的路径必须配成相对路径或可配置前缀,否则换域名就白屏;二是跨域访问影像接口时,响应头要允许前端所在域。
// 在页面中初始化 Weasis Web 查看器 // containerId 指定挂载节点,studyUrl 指向后端影像接口 const viewer = new WeasisViewer({ containerId: 'viewer-root', studyUrl: '/api/study/1.2.840.xxxxx', locale: 'zh-CN', enableMeasurement: true }); viewer.load().catch(err => { // 加载失败时优先看网络面板里影像接口的返回码 console.error('影像加载失败', err); });这里的studyUrl是前后端约定的影像入口,enableMeasurement控制是否开启测量工具。逻辑上,初始化只负责挂载和配置,真正的影像请求在load()时才发出,这样页面首屏不会被大序列拖住。参数说明:locale影响界面文案,containerId必须指向一个已存在的 DOM 节点,否则初始化会静默失败——这是新手最常踩的坑之一。
2.3 两种形态的取舍对照
| 维度 | 桌面形态 | Web 形态 |
|---|---|---|
| 部署成本 | 每台机器装一次 | 服务端部署,客户端零安装 |
| 影像来源 | 本地文件或标准协议 | 后端接口按需传输 |
| 性能上限 | 受本机内存和显卡影响 | 受网络带宽和浏览器限制 |
| 适用场景 | 固定工作站、大批量序列 | 多终端、远程查看、嵌入现有系统 |
选型建议:如果用户集中在几个固定工位、影像序列又特别大,桌面形态更稳;如果要覆盖多终端、还要嵌进已有 Web 系统,Web 形态更合适。两者不是互斥的,同一套后端可以同时服务两种前端。
3. 把影像接进来:DICOM 加载、缓存与渲染参数
影像能不能顺利打开,八成取决于加载链路和缓存策略,而不是渲染本身。这一章把从「影像在哪」到「屏幕上出现第一帧」的路径拆开讲。
3.1 影像来源的三种接法
第一种是本地文件系统,直接把目录或文件路径交给查看器,适合离线阅片和教学。第二种是标准网络协议,通过配置服务端地址和端口去查询、拉取,适合对接已有影像系统。第三种是自定义接口,由你自己的后端把影像转成查看器能消费的格式,适合 Web 形态和需要做权限控制的场景。
# 通过配置文件指定网络影像来源 # 常见做法是把地址、端口、调用方式写进配置,而不是硬编码 cat > /data/weasis/conf/source.properties <<'EOF' source.type=dicomweb source.endpoint=https://imaging.internal/api source.authMode=token source.timeoutMs=15000 EOF这段配置的关键在source.type,它决定查看器用哪种协议去取影像;timeoutMs设得太短,大序列会在传输中途断掉,设得太长,用户会以为卡死。参数说明:authMode控制鉴权方式,实际值要和你后端的能力对齐,不要照抄。
3.2 缓存目录与内存参数怎么定
缓存是二次打开速度的决定因素。默认缓存往往落在用户目录下,空间有限,序列一多就被挤掉。我一般会把缓存目录指到独立数据盘,并给它留出足够空间。内存方面,堆上限要能容纳「同时打开的最大序列解码后的大小」,经验值是单序列峰值乘以并发数再留 30% 余量。
# 调整缓存与内存相关参数 java -Xmx4g -Xms1g \ -Dweasis.cacheDir=/data/weasis-cache \ -Dweasis.cacheMaxSize=20g \ -jar weasis-launcher.jar-Xms设成和-Xmx接近可以减少堆伸缩带来的抖动;cacheMaxSize超过磁盘可用空间会导致写入失败,进而表现为「影像打开一半报错」。参数说明:这些值没有万能公式,先按单序列峰值估算,再根据实际监控调整。
3.3 渲染相关的几个必调项
渲染阶段最影响体验的是窗宽窗位、插值和多序列布局。窗宽窗位决定灰度映射范围,默认值对某些模态并不合适;插值方式影响缩放后的观感,平滑插值好看但更吃性能;多序列布局决定一次能同屏看几个序列,直接关系到阅片效率。
// 设置渲染相关参数 viewer.setWindowLevel({ width: 400, center: 40 }); viewer.setInterpolation('bilinear'); viewer.setLayout({ rows: 2, cols: 2 });setWindowLevel里的 width 和 center 要按模态给,CT 腹部和肺窗差别很大;setInterpolation在性能吃紧的机器上可以换成最近邻;setLayout的 rows 和 cols 乘积就是同屏序列数,超过 4 个在小屏幕上基本没法看。参数说明:这些设置可以在加载后动态改,不必重启。
4. 避坑与排查:那些让阅片突然翻车的细节
这一章是我自己踩过、也见别人踩过的坑,按「现象 → 原因 → 解决」写,方便对照排查。
4.1 影像打开一半报错
现象:序列加载到某个位置停住,控制台报读取失败。原因:多半是缓存目录空间不足或权限不对,写入中断。解决:先看缓存目录剩余空间和属主,把cacheDir指到有空间且当前用户可写的路径,再重试。
4.2 Web 端白屏但接口正常
现象:页面挂载节点是空的,网络面板里影像接口返回 200。原因:静态资源路径配成了绝对路径,换域名或加前缀后加载不到。解决:把资源前缀改成可配置项,部署时统一注入,别写死。
4.3 大序列导致内存溢出
现象:打开增强序列时进程直接退出,日志里有内存相关报错。原因:堆上限小于解码后序列的实际占用。解决:先估算单序列峰值,把-Xmx调上去,同时确认没有同时打开过多序列。
4.4 测量数值和预期对不上
现象:长度或角度测量结果和参考值有偏差。原因:像素间距等元数据没被正确读取,或缩放后没做坐标换算。解决:检查影像元数据是否完整,确认测量是在原始坐标还是显示坐标上做的,必要时在渲染层做换算。
4.5 跨域请求被拦
现象:Web 端影像接口报跨域错误。原因:后端响应头没允许前端所在域。解决:在影像接口的响应里加上允许的来源,或把前端和接口放到同域下,减少配置面。
提示:排查顺序建议从「网络请求是否成功」到「数据是否完整」再到「渲染参数是否合适」,不要一上来就怀疑渲染代码。
5. 进阶:把 Weasis 嵌进现有系统与批量处理技巧
当你已经能稳定打开影像,下一步通常是想把它嵌进现有系统,或者用它做批量处理。嵌入的关键是接口边界:让查看器只负责「给我影像地址,我负责显示」,权限、审计、影像存储都留在你自己的后端。这样升级查看器时不会牵动整个系统。
批量处理则适合教学和科研场景。常见做法是写一个脚本,遍历目录里的影像,逐个交给查看器打开并导出截图或测量结果。下面是一个批量导出的思路片段:
# 批量处理:遍历目录,逐个打开并导出 for study in /data/studies/*; do # 每个 study 目录当作一次独立加载 java -Xmx2g -Dweasis.cacheDir=/data/weasis-cache \ -jar weasis-launcher.jar \ "dicom:get?dir=$study" \ --export=/data/exports/$(basename "$study").png done这段脚本里,--export是导出动作,实际参数名要以你所用版本的帮助信息为准;循环里每个 study 独立启动一次进程,好处是互不影响,代价是启动开销大,序列特别多时可以考虑复用进程。参数说明:导出格式和分辨率通常也能配,按需查帮助。
验证嵌入是否成功,我一般看三件事:一是影像能按预期加载,二是测量和布局操作不报错,三是关闭后资源能正常释放。最后一条最容易被忽略,长期运行的系统里,资源不释放会慢慢把内存吃光。
说个我自己的教训:早期我总想一次把所有功能都开给用户,结果界面复杂到没人用。后来改成按角色给 profile,普通用户只留浏览和测量,高级功能单独开,反而稳定了。做影像工具,克制比堆功能更重要。希望帮到你。
本文还有配套的精品资源,点击获取