公司动态

手把手搭建DICOM PACS与Worklist测试环境:Orthanc与开源工具实战

📅 2026/8/3 5:37:40
手把手搭建DICOM PACS与Worklist测试环境:Orthanc与开源工具实战
1. 从零到一构建一个可用的DICOM PACS与Worklist环境如果你正在涉足医学影像处理、医疗设备研发或者需要搭建一个用于测试、教学或小规模应用的影像归档与通信系统那么亲手搭建一套DICOM PACS和Worklist环境无疑是一个极具价值的实践。这不仅仅是运行几个安装包那么简单它意味着你需要深入理解DICOM协议栈中几个核心服务如C-STORE, C-FIND, C-MOVE是如何协同工作的以及Worklist SCP如何扮演“任务调度中心”的角色。市面上虽然有罗万PACS、云PACS系统等成熟商业方案但自己搭建能让你获得对底层流程的绝对控制权无论是为了调试一台超声设备、开发一个AI辅助诊断模块还是构建一个私有的研究数据库都至关重要。很多人一听到“环境搭建”就觉得头大联想到Python环境、Java环境、深度学习环境那些繁琐的依赖和配置。确实DICOM环境的搭建有其复杂性它涉及网络通信、服务端/客户端架构、以及严格的协议合规性。但别担心我们的目标不是构建一个医院级的高可用集群而是一个在单机或局域网内能够稳定运行、支持标准DICOM操作的基础环境。我将以最流行的开源工具包为核心带你一步步走通全流程重点不是“点下一步”而是解释清楚每一个配置项背后的“为什么”以及我在多次搭建中踩过的那些坑。你会发现一旦理清了脉络它比配置一个复杂的深度学习框架比如PyTorch或YOLOv5要直观得多。2. 核心组件选型为什么是Orthanc和dcm4chee搭建DICOM环境首先面临的是工具选型。就像搭建网站你会纠结于LAMP还是LNMP一样DICOM领域也有几个久经考验的开源方案。经过对比和实际项目验证我主要推荐以下两种组合它们分别适用于不同的侧重点。方案一Orthanc 自制Worklist SCP推荐给开发者和研究者Orthanc (PACS Server)这是一个轻量级、跨平台Windows, Linux, macOS、基于RESTful API的DICOM服务器。它的最大优点是“简单”。它本身就是一个完整的PACS包含了存储C-STORE SCP、查询/检索C-FIND/C-MOVE SCP服务。你几乎不需要配置下载对应平台的二进制包运行即可启动一个DICOM服务端。它的Web管理界面非常直观可以方便地查看接收到的影像、进行简单的DICOM操作。对于需要快速搭建一个接收和查看影像的环境Orthanc是首选。自制Worklist SCPOrthanc默认不包含Worklist SCP功能。Worklist工作列表是DICOM Modality Worklist服务用于向CT、MRI等影像设备Modality提供患者信息和检查预约信息。要实现它我们需要额外部署一个Worklist SCP服务。这里灵活性很高你可以用DCMTK工具包中的wlmscpfs工具快速搭建一个基于文件系统的静态Worklist也可以用Python的pynetdicom库编写一个动态的、可以从数据库读取信息的Worklist服务。对于测试和基础功能验证静态Worklist就足够了。为什么选这个组合因为它模块清晰、依赖少、易于调试。Orthanc负责“存”和“取”我们自建的Worklist负责“派活”。两者通过DICOM协议通信职责分离。当Worklist服务出现问题时你可以单独重启或调试它而不会影响PACS中已存储的影像数据。这种架构非常适合开发和集成测试。方案二dcm4chee一体化企业级方案dcm4chee这是一个功能极其强大的、基于Java EE的完整PACS归档系统。它“全家桶”式地包含了PACS归档、Worklist SCP、放射科信息管理系统RIS视图、甚至图像查看器。如果你需要一个更接近医院生产环境的、功能全面的系统dcm4chee是开源领域的不二之选。挑战功能强大的代价是复杂度高。它依赖于WildFly/JBoss应用服务器、PostgreSQL或MySQL数据库部署和配置步骤较多对系统资源内存的要求也更高。初次搭建可能需要花费更多时间来解决环境依赖和配置问题。决策建议如果你是初学者或者目标是快速建立一个用于接收、存储、查看DICOM影像并能与设备进行Worklist交互的测试环境我强烈建议从方案一Orthanc 自制Worklist开始。它能让你以最小的代价理解整个数据流。本文后续的详细搭建步骤也将以这个组合为主线。当你需要更复杂的患者管理、权限控制、工作流引擎时再考虑迁移到dcm4chee。除了这两个你可能还会看到GDCM、DCMTK等工具包它们更多是用于处理DICOM文件的命令行工具和开发库而不是开箱即用的服务端。在我们的搭建中也会用到DCMTK中的一些工具来进行服务测试和验证。3. 实战搭建Orthanc PACS服务器部署与配置让我们开始动手。首先完成PACS部分的搭建这是整个环境的数据核心。3.1 Orthanc的安装与启动下载访问Orthanc的 官方GitHub发布页面 根据你的操作系统下载最新的稳定版。对于Windows用户直接下载.exe安装程序或.zip压缩包。Linux用户可以选择对应发行版的包如.debfor Ubuntu或通用压缩包。安装/解压Windows下运行安装程序或解压ZIP包到一个不含中文和空格的路径例如D:\Orthanc。Linux下使用包管理器安装或解压到/opt/orthanc之类的目录。首次运行与配置Windows进入Orthanc目录双击Orthanc.exe。它会启动一个命令行窗口和一个Web服务器。默认情况下Orthanc的Web界面地址是http://localhost:8042。在浏览器中打开它你就能看到管理界面。Linux如果是包安装服务可能已经启动。如果是压缩包进入目录后运行./Orthanc。同样访问http://localhost:8042。关键配置配置文件Orthanc的详细行为由配置文件控制。默认情况下它会在运行目录寻找orthanc.json。你可以从官方提供的 配置文件模板 开始。对于基础搭建我们最需要关注两个部分DICOM通信配置确保Orthanc监听正确的端口以便接收设备发送来的影像。{ DicomServer : { Port : 4242, // Orthanc作为DICOM SCP服务端监听的端口这是默认值 RemoteAccessAllowed : true // 允许非本机的设备连接测试时需要 } }存储路径查看StorageDirectory配置项它指定了接收到的DICOM文件存放的物理路径。默认通常在程序所在目录的OrthancStorage文件夹下。踩坑记录1端口冲突与防火墙。4242是Orthanc的默认DICOM端口。请确保该端口没有被其他程序占用。在Windows上可以用netstat -ano | findstr :4242检查。更常见的问题是防火墙阻止。在测试初期为了简化可以暂时在防火墙中为Orthanc程序或4242端口添加入站规则。在生产环境中则需要严格规划网络安全策略。3.2 验证PACS服务是否就绪安装完成后我们需要验证Orthanc是否能正常接收DICOM影像。这里我们需要一个DICOM客户端工具来模拟一台CT或MRI设备发送影像。获取测试工具使用DCMTK工具包中的storescu.exeWindows或storescuLinux。你可以从DCMTK官网下载编译好的二进制包或源码编译。准备测试影像你需要一个标准的DICOM文件.dcm后缀。可以从一些公开的医学影像数据集如The Cancer Imaging Archive - TCIA下载或者使用DCMTK自带的dcmodify工具创建一个简单的测试文件。发送测试打开命令行切换到DCMTK工具所在目录执行以下命令# 语法storescu -aet YOUR_AE_TITLE -aec ORTHANC_AE_TITLE ORTHANC_IP ORTHANC_PORT DICOM_FILE storescu -aet MY_SCU -aec ORTHANC localhost 4242 test.dcm-aet MY_SCU设置发送端客户端的AE Title应用实体标题可以任意命名如MY_SCU。-aec ORTHANC设置接收端服务器端即Orthanc的AE Title。这是关键Orthanc默认的AE Title就是ORTHANC。如果不对应连接会被拒绝。localhost和4242Orthanc服务器的地址和DICOM端口。test.dcm你要发送的DICOM文件路径。检查结果如果命令执行成功通常返回I: Association Accepted等提示回到Orthanc的Web界面 (http://localhost:8042)点击左侧的Orthanc Explorer。你应该能在All studies或All instances中看到刚刚上传的影像。点击可以查看缩略图甚至进行简单的窗宽窗位调整。至此你的PACS存储服务已经搭建并验证成功。它已经可以接收来自任何标准DICOM设备的影像了。4. 构建DICOM Modality Worklist SCP服务Worklist服务是连接医院信息系统HIS/RIS和影像设备的桥梁。设备在扫描前会向Worklist SCP查询“今天有哪些患者的检查要做”SCP返回患者ID、姓名、性别、出生日期、检查项目等信息。设备操作员只需从列表中选择避免了手动输入错误。4.1 使用DCMTK搭建静态文件Worklist SCP对于测试和演示最简单的方法是使用DCMTK的wlmscpfs工具它从一个文件系统目录读取.wl文件一种特定格式的Worklist文件来提供信息。准备Worklist数据文件首先你需要创建一个包含Worklist信息的文件。DCMTK提供了一个示例工具dump2dcm可以将文本文件转成DICOM格式。但更简单的方法是直接使用一个文本编辑器按照DCMTK期望的格式创建一个.wl文件。例如创建一个worklist.wl文件内容如下# This is a comment # PatientID, PatientName, PatientBirthDate, PatientSex, StudyInstanceUID, AccessionNumber, StudyDescription 12345, Doe^John, 19700101, M, 1.2.3.4.5.6.7.8.9, ACC0001, Chest PA 67890, Smith^Jane, 19850515, F, 9.8.7.6.5.4.3.2.1, ACC0002, Brain MRI注意这里的格式非常简化。实际DICOM Worklist包含大量标签如(0010,0010)患者姓名(0010,0020)患者ID等。wlmscpfs工具要求文件是纯文本但每行的字段顺序和含义需要与它内部解析逻辑匹配。最可靠的方法是参考DCMTK文档或源码中的例子。一个更“标准”的方法是先用findscu工具从一个真实的Worklist SCP查询一次将返回的DICOM数据用dcmdump输出为文本然后模仿其结构。启动Worklist SCP服务使用wlmscpfs工具启动服务。假设你的worklist.wl文件放在D:\WorklistData目录。# 语法wlmscpfs [选项] 端口 数据目录 wlmscpfs -df -su WORKLIST_SCP 104 D:\WorklistData-df启用调试日志方便查看连接和查询过程。-su WORKLIST_SCP设置本Worklist SCP服务的AE Title为WORKLIST_SCP。记住这个名称设备端需要用它来连接。104DICOM标准中为Worklist服务推荐的默认端口。注意这个端口不能与Orthanc的4242端口冲突。D:\WorklistData存放.wl文件的数据目录路径。验证Worklist服务同样使用DCMTK工具findscu来模拟一台设备进行查询。# 语法findscu -aet MY_MODALITY -aec WORKLIST_SCP -k 查询键值对 SERVER_IP SERVER_PORT findscu -aet MY_CT -aec WORKLIST_SCP -k “PatientName” -k “PatientID” localhost 104-aet MY_CT模拟设备的AE Title。-aec WORKLIST_SCP指定要查询的Worklist SCP的AE Title必须与启动wlmscpfs时设置的-su参数一致。-k指定查询条件。这里PatientName和PatientID表示查询所有患者空值匹配。你可以添加条件如-k “PatientID12345”。如果服务正常命令行会输出查询到的患者列表信息包含上面文件中定义的字段。踩坑记录2AE Title匹配与端口监听。DICOM通信严格校验AE Title。findscu中的-aec参数必须与wlmscpfs启动时的-su参数完全一致包括大小写。此外确保wlmscpfs启动后在104端口上成功监听可用netstat -ano | findstr :104验证。如果设备查询无响应首先检查这两点。4.2 进阶使用pynetdicom构建动态Worklist SCP静态文件的方式虽然简单但无法动态更新。在实际应用中Worklist数据通常来自医院的HIS/RIS数据库。这时我们可以用Python的pynetdicom库来编写一个灵活的Worklist SCP。环境准备确保已安装Python然后使用pip安装pynetdicom。pip install pynetdicom编写一个简单的Worklist SCP脚本创建一个Python文件例如my_worklist_scp.py。from pynetdicom import AE, evt from pynetdicom.sop_class import ModalityWorklistInformationFind from pydicom.dataset import Dataset # 定义处理C-FIND请求的事件处理器 def handle_find(event): # event.identifier 包含了设备发来的查询条件Dataset ds event.identifier # 这里模拟从数据库查询。我们根据条件返回一个固定的列表。 # 1. 构建响应数据集 response_ds Dataset() response_ds.PatientID ‘12345’ response_ds.PatientName ‘Doe^John’ response_ds.PatientBirthDate ‘19700101’ response_ds.PatientSex ‘M’ response_ds.StudyInstanceUID ‘1.2.3.4.5.6.7.8.9’ response_ds.AccessionNumber ‘ACC0001’ response_ds.StudyDescription ‘Chest PA’ # ... 设置其他需要的DICOM标签 # 2. 可以返回多个匹配项这里只返回一个作为示例 yield (0xFF00, response_ds) # 0xFF00 表示Pending还有更多结果最后一个结果后应返回 (0x0000, None) # 主程序 ae AE(ae_title‘MY_WORKLIST_SCP’) # 设置本SCP的AE Title ae.add_supported_context(ModalityWorklistInformationFind) # 支持Worklist查询服务 ae.add_requested_context(ModalityWorklistInformationFind) # 关联事件处理器 handlers [(evt.EVT_C_FIND, handle_find)] # 启动服务器监听104端口 print(“Starting Worklist SCP on port 104...”) ae.start_server((‘0.0.0.0’, 104), evt_handlershandlers)运行与测试运行这个Python脚本。它会在104端口启动一个Worklist SCP。使用之前提到的findscu工具进行测试将-aec参数改为MY_WORKLIST_SCP。你应该能收到脚本中定义的患者信息。这种方式的优势是你可以在handle_find函数中连接任何数据库如MySQL、PostgreSQL执行复杂的查询逻辑动态生成Worklist响应完全满足生产环境的需求。5. 设备配置与端到端流程测试环境搭建好后最终目的是让真实的或模拟的影像设备能够使用。这里我们分为两步配置设备或模拟器和进行端到端流程测试。5.1 配置DICOM设备通信参数无论是真实的CT、MRI还是用于测试的模拟器如DCMTK的storescu、findscu或者更图形化的工具如Osirix的Horos、OFFIS的DICOMscope都需要配置以下关键参数才能与我们的环境通信本地AE Title (Local AET)设备自身的标识如MY_CT_01。在Worklist查询和影像发送时会作为源AET。目标AE Title (Remote/PACS AET)对于发送影像到PACS目标AET是Orthanc的AE TitleORTHANC。对于从Worklist查询患者列表目标AET是Worklist SCP的AE TitleWORKLIST_SCP静态文件方式或MY_WORKLIST_SCPPython动态方式。目标IP地址 (Remote IP)运行Orthanc和Worklist SCP的计算机的IP地址。如果是同一台机器用127.0.0.1或localhost。目标端口 (Remote Port)PACS (Orthanc):4242Worklist SCP:104在真实设备的管理界面通常有DICOM Setup、Network Config等菜单中你需要添加一个或多个“DICOM节点”DICOM Node将上述参数填入。通常需要分别配置一个用于Worklist查询的节点和一个用于影像发送的节点。5.2 模拟端到端工作流我们可以用命令行工具完整模拟一次设备的工作流程步骤一查询Worklist。设备开机后首先查询Worklist获取当天预约的患者列表。findscu -aet MY_CT -aec WORKLIST_SCP -k “ScheduledProcedureStepStartDate20231027” -k “ModalityCT” localhost 104这里增加了检查日期和检查模态的查询键更符合实际场景步骤二选择并执行检查。操作员在设备控制台上从返回的列表中选择患者“Doe^John”PatientID: 12345进行扫描。步骤三发送影像至PACS。检查完成后设备将生成的DICOM影像发送到PACS。storescu -aet MY_CT -aec ORTHANC -v localhost 4242 CT_Scan_Images/-v启用详细模式CT_Scan_Images/是一个包含多个DICOM文件的目录步骤四在PACS中验证。打开Orthanc的Web界面 (http://localhost:8042)你应该能在“All studies”中看到来自MY_CT设备发送的、患者ID为12345的影像序列。可以点击查看、下载或进行简单的处理。这个流程的跑通标志着你搭建的DICOM PACS和Worklist环境已经具备了核心的互联互通能力。6. 常见问题排查与性能调优心得搭建过程很少一帆风顺。下面是我在多次部署中遇到的一些典型问题及解决思路。6.1 连接失败Association Rejected/Aborted这是最常见的问题表现为设备无法连接到SCP或在连接建立后立即被拒绝。检查AE Title这是首要怀疑对象确保客户端设备/模拟器配置的“目标AE Title”Called AE Title与服务器端Orthanc/Worklist SCP实际设置的AE Title完全一致包括大小写和空格。Orthanc默认是ORTHANC静态Worklist SCP我们用-su指定动态的需要在代码中指定。检查IP和端口确认IP地址正确如果是局域网用本机IP而非localhost并且端口号无误。使用netstat -anoWindows或ss -tulnpLinux查看目标端口是否处于LISTEN状态。检查防火墙临时关闭防火墙或添加规则放行对应的端口4242,104。查看服务器日志Orthanc的控制台窗口、wlmscpfs的命令行输出、Python脚本的打印信息都会包含详细的错误原因例如“No acceptable presentation context”不支持的服务类这通常意味着SCP没有添加对应的SOP Class支持如ModalityWorklistInformationFind。6.2 Worklist查询无结果或结果错误设备能连上Worklist SCP但查询不到数据或返回的数据字段不对。静态文件格式错误如果使用wlmscpfs确保你的.wl文件格式完全正确。一个字段错位就会导致整个解析失败。建议先用一个最简单的、只有一两条记录的文件测试。查询条件不匹配设备发送的查询条件如PatientID、AccessionNumber可能与你Worklist SCP中存储的数据不匹配。确保你的测试数据包含了设备查询中可能用到的关键字段。动态SCP逻辑错误如果是自编的Python SCP在handle_find函数中打印event.identifier查看设备到底发送了什么查询键。确保你的响应数据集response_ds包含了查询要求返回的所有必需属性。6.3 Orthanc存储空间与性能存储路径定期检查Orthanc配置文件中的StorageDirectory。确保所在磁盘有足够空间。DICOM影像文件体积庞大很容易撑满磁盘。索引数据库Orthanc默认使用SQLite存储元数据索引。对于研究或小型应用完全足够。如果数据量极大数十万以上研究可以考虑在配置文件中将其切换到PostgreSQL以获得更好的并发性能。内存使用Orthanc本身非常轻量。但在通过Web界面同时预览大量影像时浏览器会加载图像数据这可能对服务器带宽和客户端内存有要求。对于大量数据的浏览考虑使用其内置的Orthanc Explorer的“分页”功能或者集成更专业的Web影像查看器如OHIF Viewer。6.4 关于“云PACS”与扩展思考现在“云PACS”是个热词。我们搭建的这个本地环境其实就是云PACS最核心的、去掉了云部署和弹性伸缩部分的基础。所谓的云PACS系统源码其核心也无非是实现了DICOM SCP/SCU服务的服务器程序加上Web前端、数据库和用户管理。基于我们现有的Orthanc你已经可以做一些“云化”的尝试远程访问通过配置路由器端口转发和Orthanc的RemoteAccessAllowed等安全设置可以让授权的远程设备发送影像到你的服务器。RESTful APIOrthanc提供了极其完善的REST API。你可以用任何编程语言Python、Java等编写脚本自动上传、查询、下载影像实现与AI推理服务如YOLOv5、医学分割模型的流水线集成。与高级前端集成将Orthanc作为后端搭配前端的OHIF Viewer等开源影像工作站可以快速构建一个功能强大的Web版PACS阅片系统。搭建环境只是第一步理解其协议和架构后你就能根据实际需求像搭积木一样组合不同的工具和服务。从一台设备的测试到一个科室的试用再到一个复杂研究平台的基石这套基础环境都能提供可靠的支撑。关键在于通过亲手搭建你获得的不是一堆模糊的概念而是实实在在的、可验证可调试的控制能力。下次当设备工程师或软件开发商和你讨论接口问题时你就能清晰地指出问题可能出在AE Title、端口还是SOP Class上这种底层的自信是单纯使用商业系统无法给予的。