初次使用dcm4che-tool-findscu做查询

前言

关于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 title
		rq.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和por
		conn.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为空,默认StudyRoot
			return 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) 发送影像给己方。
			// 默认Patient
			main.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;

			@Override
			public 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)); // 患者唯一ID
		System.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)); // 检查ID
		System.out.println("StudyInstanceUID : " + data.getString(Tag.StudyInstanceUID)); // Study Instance UID 检查实例号,用于标识检查的唯一ID
		System.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 Model
			configureRetrieve(main); // 设置检索级别
			configureCancel(main); // 配置 --cancel
			main.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.测试

	@Test
	void findscuTest() {
		Attributes attrs = new Attributes(1);
		// 查询条件 相当于命令 findscu -c DCM4CHEE@192.168.100.55:11112 -m ModalitiesInStudy=MR
		attrs.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请求

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 27
    评论
dcm4che-tool-common.jar是一个Java库文件,属于dcm4che(DICOM for Java)项目的一部分。DICOM是医疗图像和通信的国际标准,dcm4che项目旨在为Java开发者提供处理DICOM图像和通信的工具。 dcm4che-tool-common.jar文件包含了一些公共的工具和功能,用于支持DICOM图像的处理和操作。它提供了一系列的方法和类,可以用于解析和读取DICOM文件、创建和修改DICOM图像、执行DICOM操作,以及处理DICOM标签、图像像素等等。 使用dcm4che-tool-common.jar,开发者可以轻松地在Java应用程序中集成DICOM功能。通过导入该库文件,开发者可以创建一个DICOM图像解析器,将DICOM图像文件读取到Java程序中,并进行进一步的处理和分析。同时,开发者也可以使用该库文件进行DICOM图像的创建和修改,包括添加、删除和更新DICOM标签、像素数据以及其他相关信息。 除此之外,dcm4che-tool-common.jar还提供了一些实用工具,用于执行DICOM操作,比如发送和接收DICOM图像,查询和检索DICOM存储服务器中的图像,以及与其他DICOM设备的通信等等。 总之,dcm4che-tool-common.jar是dcm4che项目中的一个库文件,提供了一系列的工具和功能,用于支持Java开发者处理和操作DICOM图像和通信。它使得开发者可以更加便捷地在Java应用程序中集成DICOM功能,并实现DICOM图像的解析、创建、修改以及与其他DICOM设备的通信等等操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 27
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值