前言

关于dcm4che的介绍就不多做阐述了,很多博客都有很详细的介绍。
这里记一次使用dcm4che工具包中的findscu做查询。
前提是已经在安装好dcm4che服务,具体安装步骤也不多做阐述了。


dcm4che-tool-findscu

github上有开源项目
地址:https://github.com/dcm4che/dcm4che/tree/master/dcm4che-tool/dcm4che-tool-findscu

步骤

1.新建一个spring boot项目
2.引入findscu所需依赖

        <dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId></dependency><dependency><groupId>commons-cli</groupId><artifactId>commons-cli</artifactId><version>1.4</version></dependency><dependency><groupId>org.dcm4che</groupId><artifactId>dcm4che-core</artifactId><version>5.22.5</version></dependency><dependency><groupId>org.dcm4che</groupId><artifactId>dcm4che-net</artifactId><version>5.22.5</version></dependency><dependency><groupId>org.dcm4che.tool</groupId><artifactId>dcm4che-tool-common</artifactId><version>5.22.5</version></dependency>

3.将开源的java代码:FindSCU.java和配置文件:messages.properties拷贝到spring boot项目中,结构如下:

4.在FindSCU类中,有一个main方法,是通过命令查询的,github上给出了命令的格式和例子。
格式:

例子:

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,本文不记录这些操作

5.代码(用配置keys的方法代替命令查询)
读取messages.properties文件配置

private static ResourceBundle rb = ResourceBundle.getBundle("static.messages");

配置远程连接AE title、address、port

private static void configureConnect(Connection conn, AAssociateRQ rq) throws ParseException {// 获取title属性值String title = rb.getString("title");if (StringUtils.isBlank(title)) {throw new ParseException("title cannot be missing");}// 设置AE titlerq.setCalledAET(title);// 读取host和port属性值String host = rb.getString("host");String port = rb.getString("port");if (StringUtils.isBlank(host) || StringUtils.isBlank(port)) {throw new ParseException("host or port cannot be missing");}// 设置host和porconn.setHostname(host);conn.setPort(Integer.parseInt(port));}

设置Information Model

private static void configureServiceClass(FindSCU main) throws ParseException {main.setInformationModel(informationModelOf(), IVR_LE_FIRST, queryOptionsOf());}
private static InformationModel informationModelOf() throws ParseException {try {String model = rb.getString("model");// 如果model为空,默认StudyRootreturn StringUtils.isNotBlank(model) ? InformationModel.valueOf(model) : InformationModel.StudyRoot;} catch (IllegalArgumentException e) {throw new ParseException(MessageFormat.format(rb.getString("invalid-model-name"), rb.getString("model")));}}
private static String[] IVR_LE_FIRST = new String[] { "1.2.840.10008.1.2", "1.2.840.10008.1.2.1","1.2.840.10008.1.2.2" };
private static EnumSet<QueryOption> queryOptionsOf() {return EnumSet.noneOf(QueryOption.class);}

设置检索级别

private static void configureRetrieve(FindSCU main) {if (StringUtils.isNotBlank(rb.getString("level"))) {// Retrieve是指SCU通过Query 拿到信息后,要求对方根据请求级别 (Patient/Study/Series/Image) 发送影像给己方。// 默认Patientmain.addLevel(rb.getString("level"));}}

配置 --cancel

private static void configureCancel(FindSCU main) {if (StringUtils.isNotBlank(rb.getString("cancel"))) {main.setCancelAfter(Integer.parseInt(rb.getString("cancel")));}}

设置优先级

private static int priorityOf() {String high = rb.getString("prior-high");String low = rb.getString("prior-low");return StringUtils.isNotBlank(high) ? 1 : (StringUtils.isNotBlank(low) ? 2 : 0);}

打开链接

private void open()throws IOException, InterruptedException, IncompatibleConnectionException, GeneralSecurityException {as = ae.connect(conn, remote, rq);}

配置查询的keys

private void configureKeys(Attributes keys) {this.keys.addAll(keys);}

查询

private void query() throws IOException, InterruptedException {query(keys);}
private void query(Attributes keys) throws IOException, InterruptedException {DimseRSPHandler rspHandler = new DimseRSPHandler(as.nextMessageID()) {int cancelAfter = FindSCU.this.cancelAfter;int numMatches;@Overridepublic void onDimseRSP(Association as, Attributes cmd, Attributes data) {super.onDimseRSP(as, cmd, data);int status = cmd.getInt(Tag.Status, -1);if (Status.isPending(status)) {FindSCU.this.printResult(data);++numMatches;if (cancelAfter != 0 && numMatches >= cancelAfter)try {cancel(as);cancelAfter = 0;} catch (IOException e) {e.printStackTrace();}}}};query(keys, rspHandler);}

打印查询的结果
需要其他信息,继续data.getString(Tag.XX)前提是查询的时候配置了查询展示的Tag

 private void printResult(Attributes data) {String SpecificCharacterSet = data.getString(Tag.SpecificCharacterSet);// 设置编码,防止乱码if (StringUtils.isBlank(SpecificCharacterSet)) {data.setString(Tag.SpecificCharacterSet, VR.CS, "GB18030");data.setString(Tag.SpecificCharacterSet, VR.PN, "GB18030");}// 打印查询结果System.out.println("---------- patient -----------");System.out.println("PatientID : " + data.getString(Tag.PatientID)); // 患者唯一IDSystem.out.println("PatientName : " + data.getString(Tag.PatientName)); // 患者姓名System.out.println("PatientBirthDate : " + data.getDate(Tag.PatientBirthDate)); // 出生日期System.out.println("PatientSex : " + data.getString(Tag.PatientSex)); // 患者性别System.out.println("PatientWeight : " + data.getString(Tag.PatientWeight)); // 患者体重System.out.println("PregnancyStatus : " + data.getString(Tag.PregnancyStatus)); // 怀孕状态System.out.println("InstitutionName : " + data.getString(Tag.InstitutionName)); // 医院名称System.out.println();System.out.println("----------- study ------------");System.out.println("AccessionNumber : " + data.getString(Tag.AccessionNumber)); // 检查号:RIS的生成序号,用于标识做检查的次序System.out.println("StudyID : " + data.getString(Tag.StudyID)); // 检查IDSystem.out.println("StudyInstanceUID : " + data.getString(Tag.StudyInstanceUID)); // Study Instance UID 检查实例号,用于标识检查的唯一IDSystem.out.println("StudyDate : " + data.getDate(Tag.StudyDate)); // 检查日期时间System.out.println("Modality : " + data.getString(Tag.Modality)); // 检查类型System.out.println("ModalitiesInStudy : " + data.getString(Tag.ModalitiesInStudy)); // 检查类型System.out.println("PatientAge : " + data.getString(Tag.PatientAge)); // 做检查时刻的患者年龄System.out.println("StudyDescription : " + data.getString(Tag.StudyDescription)); // 检查描述信息System.out.println("BodyPartExamined : " + data.getString(Tag.BodyPartExamined)); // 检查部位System.out.println("ProtocolName : " + data.getString(Tag.ProtocolName)); // 协议名称System.out.println();}

配置开放查询方法

public static void matchingKeys(Attributes attrs) {try {FindSCU main = new FindSCU();configureConnect(main.remote, main.rq); // 设置连接ip和端口 (远程)main.remote.setTlsProtocols(main.conn.getTlsProtocols()); // 设置Tls协议main.remote.setTlsCipherSuites(main.conn.getTlsCipherSuites());configureServiceClass(main); // 设置Information ModelconfigureRetrieve(main); // 设置检索级别configureCancel(main); // 配置 --cancelmain.setPriority(priorityOf()); // 设置优先级ExecutorService executorService = Executors.newSingleThreadExecutor(); // 单线程化线程池ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); // 定时任务main.device.setExecutor(executorService);main.device.setScheduledExecutor(scheduledExecutorService);try {main.open(); // 打开链接main.configureKeys(attrs);main.query(); // 查询} finally {main.close();executorService.shutdown();scheduledExecutorService.shutdown();}} catch (ParseException | InterruptedException | IncompatibleConnectionException | GeneralSecurityException| IOException e) {e.printStackTrace();}}

6.messages.properties配置

#配置连接
title=DCM4CHEE
host=192.168.100.55
port=11112
#specifies Information Model. Supported names: PatientRoot, StudyRoot, PatientStudyOnly,
#MWL, UPSPull, UPSWatch, UPSQuery, HangingProtocol or ColorPalette. If no Information Model is specified,
#StudyRoot will be used.
model=
invalid-model-name={0} is not a supported Information Model name
#specifies retrieve level. Use STUDY for PatientRoot, StudyRoot, PatientStudyOnly by default.
level=
#cancel the query request after the receive of the specified number of matches.
cancel=
xml=write received matches as XML Infoset specified in DICOM Part 19
xsl=apply specified XSLT stylesheet to XML representation of received matches; implies -X
#优先级 默认0
prior-high=
prior-low=

7.测试

 @Testvoid findscuTest() {Attributes attrs = new Attributes(1);// 查询条件 相当于命令 findscu -c DCM4CHEE@192.168.100.55:11112 -m ModalitiesInStudy=MRattrs.setString(Tag.ModalitiesInStudy, VR.CS, "MR");// 查询展示的信息attrs.setString(Tag.PatientID, VR.LO);attrs.setString(Tag.PatientName, VR.PN);attrs.setString(Tag.PatientBirthDate, VR.DA);attrs.setString(Tag.PatientSex, VR.CS);attrs.setString(Tag.PatientWeight, VR.DS);attrs.setString(Tag.PregnancyStatus, VR.US);attrs.setString(Tag.InstitutionName, VR.LO);attrs.setString(Tag.AccessionNumber, VR.SH);attrs.setString(Tag.StudyID, VR.SH);attrs.setString(Tag.StudyInstanceUID, VR.UI);attrs.setString(Tag.StudyDate, VR.DA);attrs.setString(Tag.Modality, VR.CS);attrs.setString(Tag.PatientAge, VR.AS);attrs.setString(Tag.StudyDescription, VR.LO);attrs.setString(Tag.BodyPartExamined, VR.CS);attrs.setString(Tag.ProtocolName, VR.LO);// 查询FindSCU.matchingKeys(attrs);}

查询结果

查询成功

抽空补充findscp模拟pacs服务器接收findscu发送的c-find请求

初次使用dcm4che-tool-findscu做查询相关推荐

  1. 水泵怎么做_燃气壁挂炉初次调试,要怎么做才好?

    燃气壁挂炉由于其便利,采暖效果佳的特点,近年来受到了不少家庭的青睐.壁挂炉作为一个具备采暖于生活热水的设备,用户在初次安装调试是非常重要的,那么燃气壁挂炉初次调试的正确步骤是怎么样的呢?壁挂炉100网 ...

  2. WDA-FPM-4-用OVP做查询跳转到明细

    转载:https://www.cnblogs.com/sapSB/p/10100697.html FPM四:用OVP做查询跳转到明细 前面做了查询的UIBB配置,在这边可以直接复用,查询的feeder ...

  3. Camstar客制化开发做查询操作(Designer中存放SQL语句)

    Camstar客制化开发做查询操作,对于Sql语句的保存地方有三种(Designer中保存在Query.Portal中保存在UserQuery.直接写在代码中) 其中Portal中UserQuery容 ...

  4. 为什么MySQL做查询语句时,第一次会很慢,但是第二次,第三次就会变快

    为什么MySQL做查询语句时,第一次会很慢,但是第二次,第三次就会变快 为什么MySQL的查询事务第一次执行会很慢,第二次,第三次就会快很多呢? 在国外,有个老外这么提问 Hi, I have an ...

  5. FPM五:拆解前面的四——OVP做查询和结果

    说明:前面的例子是将list和search放到一个Feeder Class里的,这里来做拆解分步说明. 1.创建SEARCH的结构 2.创建RESULT的结构 表类型(不用表类型的话,需要自己在cla ...

  6. php如何做查询,php – 如何使用Elastica进行查询

    这应该做: // Create a "global" query $query = new Elastica_Query; // Create the term query $te ...

  7. 计算机函数公式发生额总计,如何用Excel Sumif函数做查询模板统计客户在不同时间借款的总金额...

    一个客户在不同时间借款好几笔,如何能知道他一次借款的金额?能直接查看吗?可以直接显示他总的借款金额呢?这个问题是一个网友提出的,可以看的到,连续用了三个问号.这个问题的解决方法有很多种,本教程给出的方 ...

  8. 银行使用oracle做查询,Oracle EBS ERP银行信息查询视图

    Oracle EBS ERP银行信息查询视图 CREATE OR REPLACE VIEW XXX_STD_CE_BANKINFO_V AS SELECT cbau.org_id, cba.accou ...

  9. Python连接MYSQL,并做查询操作

    import pymysql# 打开数据库连接db = pymysql.connect(host='47.104.*.*', #数据库服务器IP port=3308, user='root', pas ...

  10. oracle遍历表做查询,oracle 语句之对数据库的表名就行模糊查询,对查询结果进行遍历,依次获取每个表名结果中的每个字段(存储过程)...

    语句的执行环境是plsql的sql窗口, 语句的目的是从整个数据库中的所有表判断 不等于某个字段的记录数 . 代码如下: declare s_sql clob:=''; -- 声明一个变量,该变量用于 ...

最新文章

  1. Nature:承磊/李猛等发现产甲烷古菌的碳代谢新途径
  2. C++学习之路(六):实现一个String类
  3. Koa入门——关键知识点总结
  4. spring data jpa 的 in 查询 Specification 实现
  5. 软工 课堂作业:选出一个整数组中最大子数组
  6. Mybatis配置文件参数定义
  7. 如何修改Vs2008环境变量
  8. 【Python】Could not find a version that satisfies the requirement cv2 (from versions: ) 的解决方案
  9. 普通用户安装nginx
  10. ASP.Net WebForm温故知新学习笔记:二、ViewState与UpdatePanel探秘
  11. Atitit 组织架构的如何划分 划分方法attilax大总结
  12. MYSQL查询语句大全集锦
  13. c语言校招笔试试题,腾讯2014校园招聘C语言笔试题
  14. C++11 字符串编码转换
  15. mac dmg包签名及公证
  16. FT6206在STM32上的调试记录
  17. 背景图片随页面滚动放大缩小
  18. 【点云处理之论文狂读经典版9】—— Pointwise Convolutional Neural Networks
  19. 程序设计思维 week9 作业B-东东学打牌
  20. 定积分之积分上限函数分段问题

热门文章

  1. 手机测试的主要测试内容
  2. 安装linux时找不到硬盘,关于安装LINUX时找不到硬盘问题解决
  3. 猫眼电影的android源代码!,微信小程序入门demo之猫眼电影
  4. FlexPaper查看.swf文件的使用方法
  5. 模块已加载,但找不到入口点DLLRegisterServer
  6. 疫情下,嵌入式er该怎么进行职业规划,难点在哪?
  7. 编译bug can not be used when making a shared object; recompile with -fPIC
  8. SQLAPI++ Library 4.2.1 VS2010破解版
  9. 计算机课英语怎么读音标,【英语课堂】48个国际音标表及发音详解图
  10. [读书]《罗辑思维》第一季、第二季推荐书籍清单