解析医疗影像中的dicom文件

一、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(患者)

GroupElementTag Description中文解释数据类型(VR)
1010Patient’s Name患者姓名PN
1020Patient ID患者IDLO
1030Patient’s Birth Date患者出生日期DA
1032Patient’s Birth Time患者出生时间TM
1040Patient’s Sex患者性别CS
101030Patient’s Weight患者体重DS
1021C0Pregnancy Status怀孕状态US

(2) Study Tag(患者)

GroupElementTag Description中文解释数据类型(VR)
850Accession Number:A RIS generated number that identifies order for the Study.检查号:RIS的生成序号,用以标识做检查的次序SH
2010Study ID检查IDSH
20000DStudy Instance UID:Unique identifier for the Study.检查实例号:不同检查的唯一标识号UI
820Study Date:Date the Study started.检查日期:检查开始的日期DA
830Study Time:Time the Study started.检查时间:检查开始的时间TM
861Modalities in Study一个检查中含有的不同检查类型CS
815Body Part Examined检查的部位CS
81030Study Description检查的描述LO
101010Patient’s Age做检查时刻的患者年龄,而不是此刻患者的真实年龄AS
(3) Series Tag(序列)
GroupElementTag Description中文解释数据类型(VR)
2011Series Number:A number that identifies this Series.序列号:识别不同检查的号码IS
20000ESeries Instance UID:Unique identifier for the Series.序列实例号:不同序列的唯一标识号UI
860Modality检查模态(MRI/CT/CR/DR)CS
8103ESeries Description检查描述和说明LO
821Series Date检查日期DA
831Series Time检查时间TM
2032Image Position (Patient):
The x,y and z coordinates of the upper left hand corner of the image,in mm.
图像位置:
图像的左上角在空间坐标系中的x.y.z坐标,单位是毫米。如果在检查中,则指该序列中第一张影像左上角的坐标。
DS
2037Image Orientation (Patient):The direction cosines of the first row and the first column with respect to the patient.图像方位DS
1850Slice Thickness:Nominal slice thickness,in mm.层厚DS
201041Slice Location:Relative position of exposure expressed in mm.实际的相对位置,单位为mmDS
1823MR AcquisitionCS
1815Body Part Examined身体部位CS

(4) Image Tag(图像)

GroupElementTag Description中文解释数据类型(VR)
88Image Type:Image identification characteristics.CS
818SOP Instance UIDSOP实例UID
823Content Date:
The date the image pixel data creation started.
影像拍摄日期DA
833Content Time影像拍摄时间TM
2013Image/Instance Number:A number that identifies this image.图像码:识别图像的号码IS
282Samples Per Pixel:Number of samples (planes) in this image.图像采样率US
284Photometric Interpretation:
Specifies the intended interpretation of the pixel data.
光度计解释:
对于CT图像,用两个枚举值MONOCHROME1,MONOCHROME2 用来判断图像是否是彩色的;
MONOCHROME 1/2是灰度图,RGB则是真彩色图
CS
2810Rows : Number of rows in the image.图像的总行数,行分辨率US
2811Columns : Number of columns in the image.图像的总列数,列分辨率US
2830Pixel Spacing:
Physical distance in the patient between the center of each pixel.
像素间距:
像素中心之间的物理间距
DS
28100Bits Allocated:
Number of bits allocated for each pixel sample.Each sample shall have the same number of bits allocated.
分配的位数:
存储每一个像素值时分配的位数,每一个样本该值相同
US
28101Bits Stored:
Number of bits stored for each pixel sample.Each sample shall have the same number of bits stored.
存储的位数:有12到16列举值
存储每一个像素用的位数,每一个样本该值相同
US
28102High Bit:
Most significant bit for pixel sample data.
Each sample shall have the same high bit.
高位US
28103Pixel 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
281050Window Center窗位DS
281051Window Width窗宽DS
281052Rescale 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
281053Rescale Slope:
m in the equation specified by Rescale Intercept(0028, 1052).
Required if Rescale Intercept is present.
斜率:
该值为表达式中的m
DS
281054Rescale 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-98个字符
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,Y4个字符
IS - Integer String整型字符串表示一个整型数字的字符串,比如 “-1234567”0-9,加号 (+),减号 (-)最多12个字符
DS - Decimal String小数字符串表示定点小数和浮点小数,比如 “12345.67”, “-5.0e3”0-9, 加号 (+), 减号 (-), 最多16个字符 E, e 和半角句号(.)最多16个字符
SS - Signed Short有符号短型符号型二进制整数,长度 16 bits2个字符
US - Unsigned Short无符号短型无符号二进制整数,长度 16 bits2个字符
SL - Signed Long有符号长型有符号二进制整数4个字符
UL - Unsigned Long无符号长型无符号二进制长整数,长度 32 bits4个字符
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中

   <dependency><groupId>org.dcm4che</groupId><artifactId>dcm4che-core</artifactId><version>3.3.8</version></dependency>

然后上代码:

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对象中。

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

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

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

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

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

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

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

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


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

公众号:

在这里插入图片描述

微信号:11141004

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/521898.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

力扣大厂热门面试算法题 6-8

6. Z 字形变换&#xff0c;7. 整数反转&#xff0c;8. 字符串转换整数 (atoi)&#xff0c;每题做详细思路梳理&#xff0c;配套Python&Java双语代码&#xff0c; 2024.03.08 可通过leetcode所有测试用例。 目录 6. Z 字形变换 解题思路 边界条件 完整代码 Python Ja…

智慧园区综合运营数字化解决方案

1. 楼栋管理 2. 物业管理 3. 安防管理 4. 门禁管理 5. 停车管理 6. 能源管理 7. 环保管理 8. 园区生活服务 9. 招商管理 10. 收费中心 11. 园区地图 12. 门户网站 智慧园区软件方案&#xff1a;智慧园区软件解决方案&#xff0c;园区运营管理系统&#xff08;源码&#xff09;-…

知识图谱 | 2023年图书馆学、情报学CSSCI期刊论文主题透视

数据来源 检索平台来源期刊年份有效数据中国知网大学图书馆学报国家图书馆学刊情报科学情报理论与实践情报学报情报杂志情报资料工作数据分析与知识发现图书馆建设图书馆论坛图书馆学研究图书馆杂志图书情报工作图书情报知识图书与情报现代情报信息资源管理学报中国图书馆学报2…

形参化类 ‘Result‘ 的原始使用

在编程中&#xff0c;特别是在面向对象编程&#xff08;OOP&#xff09;中&#xff0c;当我们说“形参化类”或“参数化类”&#xff0c;我们实际上是指泛型&#xff08;Generics&#xff09;的概念。泛型允许在定义类、接口和方法时使用类型参数。这样&#xff0c;你可以创建可…

量化投资实战(三)之配对交易策略--协整模型法

点赞、关注&#xff0c;养成良好习惯 Life is short, U need Python 量化投资实战系列&#xff0c;不断更新中 1. 初识配对交易策略 配对交易&#xff08;Pairing Trading&#xff09;是指八十年代中期华尔街著名投行Morgan Stanley的数量交易员Nunzio Tartaglia成立的一个数量…

springboot+xjar加密打包部署教程

需求背景 为了跟上时代的步伐&#xff0c;为了更好的生存。开个玩笑&#xff0c;就是心血来潮&#xff0c;使用xjar加密部署jar包&#xff0c;于是就测试一下。 xjar教程 1-maven配置文件修改 首先找到自己ideal配置的maven文件夹&#xff0c;然后找到apache-maven-3.9.3\co…

微信小程序可拖拽视频播放案例

微信小程序可拖拽视频播放案例 如图所示 使用原生小程序组件 movable-area movable-view 注意movable-view必须在area内 官方组件地址 wxml <movable-area class"movableArea"><movable-view class"movableView" out-of-bounds"false&q…

SRS服务器ffmpeg 推流rtmp超时中断

ffmpeg错误显示 failed to update header with correct duration failed to update header with correct filesize. Error writing trailer of rtmp://----- broken pipe SRS日志错误显示 serve error code2056 kickoffforidle : service cycle : rtmp stream service: timeou…

YOLOv9: Learning What You Want to Learn Using Programmable Gradient Information

paper: https://arxiv.org/abs/2402.13616 code YOLOv9: Learning What You Want to Learn Using Programmable Gradient Information 一、引言部分二、问题分析2.1 信息瓶颈原理2.2 可逆函数 三、本文方法3.1 可编程梯度信息 四、实验4.1消融实验部分 今天的深度学习方法关注的…

Python之Web开发中级教程----搭建Git环境

Python之Web开发中级教程----搭建Git环境一 Git 是目前世界上最先进的分布式版本控制系统 作用&#xff1a;代码管理。方便多人协同开发&#xff1b;方便版本控制。 安装git 单人本地仓库 建立本地仓库目录 配置个人管理信息 git config –global user.email 32356105163.com…

电子商务平台中商品数据采集|API数据接口采集商品的高效性体现

电子商务平台由一个个产品所构成,通过对产品的分析可以有效发掘用户需求,优化店铺产品结构,提升客户粘性、客单价、销售利润等。 一、产品行业数据采集API接口 采集产品行业数据的核心目的是了解该产品的市场需求变化情况,常用到的数据采集指标包括产品搜索指数和产品交易指数两…

【Vue 3】

v-model 作用&#xff1a;给表单元素使用&#xff0c;双向数据绑定---->可以快速获取或设置表单元素内容 是value属性和input事件的合写 数据变化--->视图自动更新试图变化--->数据自动更新 语法&#xff1a;v-model"变量" 数据变&#xff0c;视图跟着变…