全网实现workList服务的,要么是基于C++的DCMTK、要么是基于C#的fo-dicom。想用dcm4che实现 找了好几个月都没有一个例子。无奈只能通过DCMTK和fo-dicom 实现方式并查看dcm4che源码自己实现了。经过不懈的努力总算是实现了并实际跟设备测试成功!
首先得先了解 DICOM worklist工作原理?
一、关于Worklist
在RIS与PACS的系统集成中。Wordlist的连接bai为其主要工作之一。Wordlist成像设备工作列表,它是DICOM协议中众多服务类别中的一个.它的功能是实现设备操作台与登记台之间的通讯,完成成像设备和信息系统的集成.称为BASIC WORKLIST MANAGEMENT SERVICE(简称Worklist)。
二、DICOM标准中与Worklist相关的一些基本概念
配置影像检查设备(Modality)的Worklist首先要阅读该设备的“DICOM 一致性声明(DICOM Conformance Statement)”中关于Worklist的部分,了解设备对Worklist的支持程度。而熟悉以下基本概念则有助于阅读DICOM Conformance Statement:
1、VR(Value Representation):描述了数据元素的种类(字符串、数字、日期等)以及这些值的格式。在DICOM标准第五部分Data Structures and Encoding的第25页中列出了所有的VR。
2、Data Set(数据集):一个数据集表示了一个DICOM对象,它进一步由Data Element(数据元素)组成。而数据元素包括了tag(唯一的)、值的长度以及值。数据元素中可能包含VR。
3、 数据元素类型:一个数据元素是否在一个数据集中出现,取决于该数据元素的类型。
4、 AE Title:AE Title(Application Entity Title)是配置影像检查设备DICOM服务(Worklist、Storage、Print等)必不可少的参数之一。对于某一台影像检查设备,其各个DICOM服务可以对应不同的AE Title,当然这些DICOM服务也可以对应同一个AE Title。AE Title是一个字符串,但是这个字符串在我们要配置的RIS/PACS系统的网络中必须是唯一的。因此,AE Title是这个网络中某一个(或几个)DICOM服务的唯一标识。
三、DICOM的Worklist实现的功能
fz2841585:从RIS或者其他系统下载病人信息,以免重复登记。
0753zhongwei:Worklist只是一个传输协议,DICOM的Worklist其实就是C-FIND服务,有点类似于Query/Retrieve,SCU在C-FIND命令集后面加上一些查询字段,SCP把查询结果放在C-FIND-RSP后面返回去。
tks1000:在CT或MR等工作站上,如果没有Worklist功能,新检查一个病人的时候,要输入病人全部的基本信息,这样比较麻烦,而且容易出错。有了WorkList功能后,可以直接从服务器上读取病人的基本信息,不用输入,而且不易出错。实质上还是C-FIND,不过需要MPPS等的支持。
chaoran898:DICOM的MWL是一种接口协议,至于怎样查数据,那是coding实现的事情,MWL只负责把找到的数据按DICOM标准传出去。
xiaoyilong19:我做了多台设备的Worklist,深有体会:如果设备厂家不同的话,Worklist服务端程序就要调试一番,才能让返回的数据在对方设备工作站上显示出来,否则就是出现各种情况。乱码还比较简单处理,就是怕对方什么应答都没有。实际上就是,请求,返回请求,和cs服务架构一样。
四、Worklist在Pacs中的作用与的工作原理
五、 基本设计概念和处理流程
xuyuansheng:正常的流程是,病人在HIS上注册,经hl7消息传至RIS,RIS上便有了病人的登记信息。做检查时,成像设备通过DICOM Worklist来从RIS上取得需做检查的病人列表,选择后做检查。检查完成后,图像便可以传到PACS中进行存储。在这个过程中,病人信息仅在HIS端输入一遍,但它流经RIS,Modality以及PACS。可以节省时间,减少错误,规范流程,互联互通,形成数据共享。理想的情况下,让医生专注于检查及诊断,而缩短的时间,也会提高病人的满意度。
六、总结
看到这里后大概知道 workList 其实就是一个客户端(SCU)发起C-Find请求 服务端(SCP)将这些结果按照DICOM协议返回对应的字段组合即可
接下来就该查看DCM4CHE源码了
我们现在知道了workList 其实就是C-Find请求 我们就在dcm4che源码里找关于c-find的一切内容了!
原来dcm4che源码中dcm4che-tool 有个dcm4che-tool-findscu
很是惊喜 总算找到个入口了
甚至还有命令示例,NICE!
例子:
findscu -c DCMQRSCP@localhost:11112 -m PatientName=Doe^John -m
StudyDate=20110510- -m ModalitiesInStudy=CT
github上对各个命令都有解释,这里简单解释一下这个例子
-c 代表远程连接
DCMQRSCP是指dcm4che服务的AETitle
localhost是指dcm4che服务的ip地址
11112是指dcm4che服务的端口
-m PatientName=Doe^John 代表查询患者姓名是Doe^John
-m StudyDate=20110510 代表查询患者检查时间是20110510
-m ModalitiesInStudy=CT 代表查询患者的模态是CT
命令也支持xml文件查询和结果导出xml
甚至dcm4chee 文件里有执行findscu 命令脚本!是不是感觉离成功近了一大步~~
先试试脚本命令
(本地局域网已经部署好了 dcm4chee-web 可以直接把它当作worklist scp)
确实可以建立了通讯并且可以查询 那接下来就从 FindSCU.java源码下功夫了
充分阅读源码后 将源码进行改造
直击源码里的main 方法
public static void main(String[] args) {
try {
CommandLine cl = parseComandLine(args);//解析命令
FindSCU main = new FindSCU();
CLIUtils.configureConnect(main.remote, main.rq, cl); 设置连接ip和端口
CLIUtils.configureBind(main.conn, main.ae, cl);
CLIUtils.configure(main.conn, cl);
main.remote.setTlsProtocols(main.conn.getTlsProtocols());// 设置Tls协议
main.remote.setTlsCipherSuites(main.conn.getTlsCipherSuites());
configureServiceClass(main, cl);
configureKeys(main, cl);
configureOutput(main, cl);// 设置检索级别
configureCancel(main, cl);// 配置 --cancel
main.setPriority(CLIUtils.priorityOf(cl));
ExecutorService executorService =
Executors.newSingleThreadExecutor();
ScheduledExecutorService scheduledExecutorService =
Executors.newSingleThreadScheduledExecutor();
main.device.setExecutor(executorService);
main.device.setScheduledExecutor(scheduledExecutorService);
try {
main.open();// 打开链接
List<String> argList = cl.getArgList();
if (argList.isEmpty())
main.query();// 查询 这里是重点
else
for (String arg : argList)
main.query(new File(arg));
} finally {
main.close();
executorService.shutdown();
scheduledExecutorService.shutdown();
}
} catch (ParseException e) {
System.err.println("findscu: " + e.getMessage());
System.err.println(rb.getString("try"));
System.exit(2);
} catch (Exception e) {
System.err.println("findscu: " + e.getMessage());
e.printStackTrace();
System.exit(2);
}
}
具体看query 方法
public void query( DimseRSPHandler rspHandler) throws IOException, InterruptedException {
query(keys, rspHandler);
}
private void query(Attributes keys, DimseRSPHandler rspHandler) throws IOException, InterruptedException {
as.cfind(model.cuid, priority, keys, null, rspHandler);
}
主要看懂源码的这两个地方 大概实现findscu 就有思路了
需要的maven 包
<dependency>
<groupId>org.dcm4che</groupId>