解析医疗影像中的dicom文件

admin 2025-05-25 23:27:50

一、DICOM文件概述

我们先了解一下DICOM文件是什么,干嘛用的,以及DICOM内部有哪些信息,然后再谈如何去解析这些信息并转换成java对象。

医学影像学概览 医学影像学

这一学科致力于利用X射线、电磁场、超声波等多种介质与人体相互作用原理,将人体内部结构和密度以图像形式生动展现出来。这些可视化的信息为诊断医师提供了关键的决策依据,进而对个体健康状况进行专业评估。医学影像学的研究内容广泛,既包括构建及优化医学成像系统的硬件技术,也涵盖医学图像处理的软件算法。

DICOM标准解读 DICOM(Digital Imaging and Communications in Medicine)

作为国际公认的医学数字成像与通信标准(ISO 12052),在放射医学、心血管造影及多种放射诊疗设备(如X光、CT、PET、超声、MRI等)领域中广泛应用,并逐步渗透到眼科、牙科等其他医疗分支。DICOM格式文件是存储患者受保护健康信息(PHI)的重要载体,涵盖了姓名、性别、年龄等个人数据,以及图像采集设备信息、医疗背景资料等重要参数。目前采用的标准版本为DICOM3.0,每一张图像都蕴含丰富信息,主要分为四个类别:患者信息、检查研究信息、序列信息和图像信息,每一个信息单元通过独特的双字节十六进制标签(Group, Element)标识,如(0010,0010)即代表患者的姓名。

为了方便开发人员高效地处理DICOM数据,业界涌现了一批优秀的第三方库,如基于C++的DCMTK、基于Java的dcm4che以及Python语言环境下的pydicom。它们为开发者屏蔽了底层解析复杂性,极大地提高了项目开发效率。

当前,CT、MRI、超声等先进成像技术通过精准聚焦的射线束、探测器围绕人体特定区域进行连续断层扫描,从而生成多层面图像,经由三维重建技术可叠加成三维图像,而每一层面图像及其相关头部信息均可储存在DICOM文件中。DICOM文件的结构严谨,通常由文件头和数据集合两部分构成,其中文件头包含了识别文件属性的关键信息,且每个DICOM文件必备一个文件头。

深入剖析DICOM内部信息(DICOM Tag与VR)

DICOM数据集构成了DICOM文件的核心部分,其由一系列按特定顺序排列的DICOM数据元素组成。每个数据元素最小单位称为数据元,根据TAG值从小至大排序。数据元由四部分构成:

TAG编号: 由4个字节表示,包含2字节组号和2字节元素号,例如"0010 0040"对应患者性别信息,不同组号分别指示设备通讯信息、特性参数、患者信息和图像信息参数等内容。

值表示(VR, Value Representation): 两个字节定义了该数据元的数据类型,如LO(长字符串)、IS(整型字符串)、DA(日期)等共27种不同类型。

值长度(Value Length): 记录该数据项的具体长度。

值域(Value): 实际存储的数据值。

数据元素按照信息类别可分为四大类:患者、检查研究、序列和图像 ,形成一种患者可进行多次检查,每次检查涉及多个部位系列,每个部位系列关联一张或多张影像图像的层级结构。

1.常见的TAG

(1) Patient Tag(患者)

Group

Element

Tag Description

中文解释

数据类型(VR)

10

10

Patient’s Name

患者姓名

PN

10

20

Patient ID

患者ID

LO

10

30

Patient’s Birth Date

患者出生日期

DA

10

32

Patient’s Birth Time

患者出生时间

TM

10

40

Patient’s Sex

患者性别

CS

10

1030

Patient’s Weight

患者体重

DS

10

21C0

Pregnancy Status

怀孕状态

US

(2) Study Tag(患者)

Group

Element

Tag Description

中文解释

数据类型(VR)

8

50

Accession Number:A RIS generated number that identifies order for the Study.

检查号:RIS的生成序号,用以标识做检查的次序

SH

20

10

Study ID

检查ID

SH

20

000D

Study Instance UID:Unique identifier for the Study.

检查实例号:不同检查的唯一标识号

UI

8

20

Study Date:Date the Study started.

检查日期:检查开始的日期

DA

8

30

Study Time:Time the Study started.

检查时间:检查开始的时间

TM

8

61

Modalities in Study

一个检查中含有的不同检查类型

CS

8

15

Body Part Examined

检查的部位

CS

8

1030

Study Description

检查的描述

LO

10

1010

Patient’s Age

做检查时刻的患者年龄,而不是此刻患者的真实年龄

AS

(3) Series Tag(序列)

Group

Element

Tag Description

中文解释

数据类型(VR)

20

11

Series Number:A number that identifies this Series.

序列号:识别不同检查的号码

IS

20

000E

Series Instance UID:Unique identifier for the Series.

序列实例号:不同序列的唯一标识号

UI

8

60

Modality

检查模态(MRI/CT/CR/DR)

CS

8

103E

Series Description

检查描述和说明

LO

8

21

Series Date

检查日期

DA

8

31

Series Time

检查时间

TM

20

32

Image Position (Patient):The x,y and z coordinates of the upper left hand corner of the image,in mm.

图像位置:图像的左上角在空间坐标系中的x.y.z坐标,单位是毫米。如果在检查中,则指该序列中第一张影像左上角的坐标。

DS

20

37

Image Orientation (Patient):The direction cosines of the first row and the first column with respect to the patient.

图像方位

DS

18

50

Slice Thickness:Nominal slice thickness,in mm.

层厚

DS

20

1041

Slice Location:Relative position of exposure expressed in mm.

实际的相对位置,单位为mm

DS

18

23

MR Acquisition

CS

18

15

Body Part Examined

身体部位

CS

(4) Image Tag(图像)

Group

Element

Tag Description

中文解释

数据类型(VR)

8

8

Image Type:Image identification characteristics.

CS

8

18

SOP Instance UID

SOP实例UID

8

23

Content Date:The date the image pixel data creation started.

影像拍摄日期

DA

8

33

Content Time

影像拍摄时间

TM

20

13

Image/Instance Number:A number that identifies this image.

图像码:识别图像的号码

IS

28

2

Samples Per Pixel:Number of samples (planes) in this image.

图像采样率

US

28

4

Photometric Interpretation:Specifies the intended interpretation of the pixel data.

光度计解释:对于CT图像,用两个枚举值MONOCHROME1,MONOCHROME2 用来判断图像是否是彩色的;MONOCHROME 1/2是灰度图,RGB则是真彩色图

CS

28

10

Rows : Number of rows in the image.

图像的总行数,行分辨率

US

28

11

Columns : Number of columns in the image.

图像的总列数,列分辨率

US

28

30

Pixel Spacing:Physical distance in the patient between the center of each pixel.

像素间距:像素中心之间的物理间距

DS

28

100

Bits Allocated:Number of bits allocated for each pixel sample.Each sample shall have the same number of bits allocated.

分配的位数:存储每一个像素值时分配的位数,每一个样本该值相同

US

28

101

Bits Stored:Number of bits stored for each pixel sample.Each sample shall have the same number of bits stored.

存储的位数:有12到16列举值存储每一个像素用的位数,每一个样本该值相同

US

28

102

High Bit:Most significant bit for pixel sample data.Each sample shall have the same high bit.

高位

US

28

103

Pixel Representation:Data representation of the pixel samples.Each sample shall have the same pixel representation.Enum:0000H=unsigned integer,0001H=2’ s complement.

像素数据的表现类型:一个枚举值,分别为十六进制数0000和0001.0000H = 无符号整型,0001H = 2的补码

US

28

1050

Window Center

窗位

DS

28

1051

Window Width

窗宽

DS

28

1052

Rescale Intercept:The value b in relationship between stored values(SV) and the output units.Output units = m*SV + b.Required if Modality LUT Sequence(0028, 0030) is not present.

截距:如果表明不同模态的LUT颜色对应表不存在时,则使用方程:Units = m*SV + b,计算真实的像素值到呈现像素值,其中截距为表达式中的b

DS

28

1053

Rescale Slope:m in the equation specified by Rescale Intercept(0028, 1052).Required if Rescale Intercept is present.

斜率:该值为表达式中的m

DS

28

1054

Rescale Type:Specifies the output units of Rescale Slope (0028,1053) and Rescale Intercept (0028,1052).Enum: US=Unspecified Requried if Photometric Interpretation is MONOCHROME2, and Bits Stored is greater than 1.This specifies an identity Modality LUT transformation.

输出值的单位:该值是一个枚举值

LO

2.VR数据类型

VR是DICOM标准中用来描述数据类型的,总共有27个值。

27种数据类型

数据类型(VR)

含义

允许字符

数据长度

CS - Code String代码字符串

开头结尾可以有没有意义的空格的字符串,比如 “CD123_4"

大写字母,0-9,空格以及下划线字符

最多16个字符

SH - Short String短字符串

短字符串,比如:电话号码, ID 等

最多16个字符

LO - Long String长字符串

一个字符串,可能在开头、结尾填有空格。比如 “Introduction to DICOM”

最多64个字符

ST - Short Text短文本

可能包含一个或多个段落的字符串

最多1024个字符

LT - Long Text长文本

可能包含一个或多个段落的字符串,与 LO 相同,但可以更长

最多10240个字符

UT - Unlimited Text无限制文本

包含一个或多个段落的字符串,与 LT 类似

最多(232 -2)个字符

AE - Application Entity应用实体

标识一个设备的名称的字符串,开头和结尾可以有无意义的字符。比如 “MyPCO 1”

最多16个字符

PN - Person Name病人姓名

有插入符号 (^) 作为姓名分隔符的病人姓名。比如“SMITH^JOHN” “Morrison Jones Susan^^^Ph.D,Chief Executive Officer”

最多64个字符

UI - Unique Identifier(UID)唯一标识符

一个用作唯一标识各类项目的包含UID的字符串。比如 “1.2.840.10008.1.1”

0-9和半角句号 (.)

最多64个字符

DA - Date日期

格式为 YYYYMMDD 的字符串;YYYY 代表年;MM 代表月;DD 代表日。比如 “20050822” 表示 2005 年 8 月 22 日

0-9

8个字符

TM - Time时间

格式为 HHMMSS.FRAC 的字符串。HH 表示小时(范围"00"-“23”);MM 表示分钟 (范围"00"-“59”);而 FRAC 包含秒的小数部分,即百万分之一秒, 比如 “183200.00” 表示下午 6:32

0-9和半角句号 (.)

最多16个字符

DT - Date Time日期时间

格式为 YYYYMMDDHHMMSS.FFFFFF,串联的日期时间字符串。字符串的各部分从左至右是:年-YYYY;月-MM;日-DD;小时-HH;分钟-MM;秒-SS;秒的小数-FFFFFF。比如 “20050812183000.00” 表示 2005 年 8 月 12 日 下午 18 点 30 分 00 秒

0-9,加号,减号和半角句号

最多26个字符

AS - Age String年龄字符串

符合以下格式的字符串:nnnD,nnnW,nnnM,nnnY;其中 nnn 对于 D 来说表示天数,对于 W 来说表示周数,对于 M 来说表示月数,对于 Y 来说表示岁数。比如 “018M” 表示他的年龄是 18 个月

0-9,D,W,M,Y

4个字符

IS - Integer String整型字符串

表示一个整型数字的字符串,比如 “-1234567”

0-9,加号 (+),减号 (-)

最多12个字符

DS - Decimal String小数字符串

表示定点小数和浮点小数,比如 “12345.67”, “-5.0e3”

0-9, 加号 (+), 减号 (-), 最多16个字符 E, e 和半角句号(.)

最多16个字符

SS - Signed Short有符号短型

符号型二进制整数,长度 16 bits

2个字符

US - Unsigned Short无符号短型

无符号二进制整数,长度 16 bits

2个字符

SL - Signed Long有符号长型

有符号二进制整数

4个字符

UL - Unsigned Long无符号长型

无符号二进制长整数,长度 32 bits

4个字符

AT - Attribute Tag属性标签

16 bits 无符号整数的有序对,数据元素的标签

4个字符

FL - Floating Single单精度浮点型

单精度二进制浮点数

4个字符

FD - Floating Point Double双精度二进制浮点型

双精度二进制浮点数

8个字符

OB - Other Byte String其它字节字符串

字节的字符串("其它"表示没有在VR中定义的内容)

OW - Other Word String其它单词字符串

16 bits(2字节) 单词字符串

OF - Other Float String其它浮点字符串

32 bits(4个字节) 浮点单词字符串

SQ - Sequence Items条目序列

条目的序列

UN - Unknown未知

字节的字符串,其中内容的编码方式是未知的

上面TAG数据均可通过dcm查看工具查看,也能修改:

二、java解析DICOM的TAG

导入dcm4che3到maven中

org.dcm4che

dcm4che-core

3.3.8

然后上代码:

package com.wanputech.film.util;

import com.alibaba.fastjson.JSON;

import com.wanputech.film.domain.dto.DicomInfo;

import org.apache.commons.lang.StringUtils;

import org.dcm4che3.data.Attributes;

import org.dcm4che3.data.Tag;

import org.dcm4che3.data.VR;

import org.dcm4che3.io.DicomInputStream;

import java.io.File;

import java.io.IOException;

import java.nio.charset.Charset;

import java.time.LocalDateTime;

import java.time.ZoneId;

import java.time.ZonedDateTime;

import java.time.format.DateTimeFormatter;

import java.util.Date;

import java.util.regex.Matcher;

import java.util.regex.Pattern;

/**

*

* 解析获取dcm文件信息

*

* @author dengjiajin

* @since 2024/1/10

*/

public class RadiologyParserUtil {

public static void main(String[] args) throws IOException {

String dcmPath = "D:\\radiology1\\11151\\1609000006C7_0001_0001.dcm";

DicomInfo dicomInfo = getDicomInfo(dcmPath);

System.out.println(JSON.toJSONString(dicomInfo));

}

/**

* 解析获取dcm文件信息

* @param dcmPath

* @return

*/

public static DicomInfo getDicomInfo(String dcmPath) throws IOException {

File file = new File(dcmPath);

DicomInputStream dis = new DicomInputStream(file);

Attributes attrs = dis.readDataset(-1, -1);

dis.close();

String specificCharset = attrs.getString(Tag.SpecificCharacterSet);

if (specificCharset.equals("ISO_IR 192") || specificCharset.equals("GB18030")) {

// 设置系统属性以影响dcm4che库内部的字符集转换

System.setProperty("dcm4che.charset", "GB18030");

} else if (specificCharset.equals("ISO_IR 58") || specificCharset.equals("GBK")) {

System.setProperty("dcm4che.charset", "GBK");

}

String patientName = attrs.getString(Tag.PatientName);

String patientID = attrs.getString(Tag.PatientID);

String modality = attrs.getString(Tag.Modality);

String studyDate = attrs.getString(Tag.StudyDate);

String studyTime = attrs.getString(Tag.StudyTime);

String studyInstanceUid = attrs.getString(Tag.StudyInstanceUID);

String bodyPartExaminedStr = new String(attrs.getBytes(Tag.BodyPartExamined)

, Charset.forName(attrs.getString(Tag.SpecificCharacterSet)));

DicomInfo dicomInfo = new DicomInfo();

dicomInfo.setPatientName(patientName);

dicomInfo.setPatientId(patientID);

dicomInfo.setModality(modality);

dicomInfo.setStudyDateStr(studyDate);

dicomInfo.setStudyTimeStr(studyTime);

studyDateTimeStrConverseToDate(dicomInfo);

dicomInfo.setBodyPartExamined(bodyPartExaminedStr);

dicomInfo.setAge(parseAge(attrs.getString(Tag.PatientAge)));

dicomInfo.setSex(parseSex(attrs.getString(Tag.PatientSex)));

dicomInfo.setStudyInstanceUid(studyInstanceUid);

return dicomInfo;

}

private static String parseSex(String sex) {

if ("F".equals(sex)){

return "1";

}else {

return "0";

}

}

private static String parseAge(String n) {

Integer patientAge = null;

Pattern pattern = Pattern.compile("(\\d+)Y");

Matcher matcher = pattern.matcher(n);

if (matcher.find()) {

patientAge = Integer.valueOf(matcher.group(1));

}

Pattern pattern2 = Pattern.compile("(\\d+)M");

Matcher matcher2 = pattern2.matcher(n);

if (matcher2.find()) {

patientAge = Integer.valueOf(matcher2.group(1));

patientAge = patientAge / 12;

}

Pattern pattern3 = Pattern.compile("(\\d+)D");

Matcher matcher3 = pattern3.matcher(n);

if (matcher3.find()) {

patientAge = Integer.valueOf(matcher3.group(1));

patientAge = patientAge / 365;

}

return patientAge.toString();

}

private static void studyDateTimeStrConverseToDate(DicomInfo dicomInfo) {

String studyDateStr = dicomInfo.getStudyDateStr();

String studyTimeStr = dicomInfo.getStudyTimeStr();

if (studyDateStr != null && studyTimeStr != null)

String dateTimeStr = studyDateStr + " " + studyTimeStr.substring(0, 6); // 去掉微秒部分

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd HHmmss");

LocalDateTime localDateTime = LocalDateTime.parse(dateTimeStr, formatter);

ZoneId zoneId = ZoneId.systemDefault(); // 或者指定时区 TimeZone.getDefault().toZoneId()

ZonedDateTime zonedDateTime = localDateTime.atZone(zoneId);

Date studyTime = Date.from(zonedDateTime.toInstant());

dicomInfo.setStudyTime(studyTime);

}

}

}

解析的代码主要是getDicomInfo这个方法。

这段Java代码主要功能是从DICOM文件中读取相关信息,并将其保存在一个自定义的DicomInfo对象中。

首先,通过File对象创建一个DicomInputStream,然后使用readDataset方法读取DICOM文件中的数据集,并将其保存在Attributes对象中。

根据DICOM文件中的SpecificCharacterSet属性值,设置系统属性dcm4che.charset,以影响dcm4che库内部的字符集转换。

从Attributes对象中获取并保存一些重要的DICOM属性值,如PatientName、PatientID、Modality、StudyDate、StudyTime、StudyInstanceUID和BodyPartExamined等。

创建一个DicomInfo对象,并将之前获取的DICOM属性值设置到该对象中。调用studyDateTimeStrConverseToDate方法对studyDateTimeStr进行日期时间转换,并将结果保存在DicomInfo对象中。

调用parseAge和parseSex方法分别解析PatientAge和PatientSex属性值,并将结果保存在DicomInfo对象中。

最终,这段代码将包含DICOM文件信息的DicomInfo对象返回或进行后续处理。

dcm返回的age格式是40Y,08M,24D,这种格式最后的字母分别代表Y(年),M(月),D(天),这里需要特殊处理。

领取dcm4che包、查看dcm文件工具、dcm文件模版。扫码添加我的公众号。

如果您有什么问题、或领取dcm4che包、查看dcm文件工具、dcm文件模版。扫码添加我的公众号留言或添加我的微信留言即可。届时也会分享一些日常工作遇到的难题。

公众号:

微信号:11141004