【疑难杂症2025-006】DICOM脱敏,搞了半天,和一个分割符较劲了半天

本文由Markdown语法编辑器编辑完成。

1.背景:

最近在做关于DICOM文件脱敏的需求。要求是能够根据任意给定的DICOM TAG, 来进行脱敏。

这里的TAG, 可以是TagName, 如PatientName, InstituteName等; 也可以是按照十六进制形式给出的(Group, Element)的TagID.

当我拿到一个需要脱敏的dicom文件时,我使用dcmdump查看了一下文件都有哪些TAG, 以便测试能够将指定的Tag进行脱敏。我无意中看到了这样一个Tag, 它的TagID是(fffe, e0dd), 是一个非常罕见的Tag.

在这里插入图片描述
因为曾经了解过,一般dicom文件,最大的Tag, 就是存储像素信息的tag, (7fe0,0010).
但是这里却出现了一个,大于(7fe0, 0010)的Tag, 似乎跟过去的经验不符了 (https://dicomiseasy.blogspot.com/2012/08/chapter-12-pixel-data.html)。

之前关于为什么要将PixelData的tag标签置为: (7fe0, 0010), 这里有知名博主(Dicom is Easy)的一些解释。
在这里插入图片描述
但是也只能硬着头皮,继续处理了。

但是,很奇怪,按照相同的代码,其他的常见的Tag, 无论是采用java dcm4chee的代码,还是采用python pydicom的代码,都可以正常地脱敏。唯独对这个奇怪的Tag, 无论如何都无法将其脱敏掉。

2. 脱敏过程:

2.1 java -> dcm4chee

在dcm4chee的项目(https://github.com/dcm4che/dcm4che)中,dicom所有的Tag, 都会存储在一个叫做Attributes的类对象中。
如果要去除相应的tag, 只需要在另一个类Tag.class中找到这个TagName对应的int类型的数字,便可以调用Attributes类提供的remove方法来脱敏。

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

比如,如果想要将PatientName这个标签脱敏,那么只需要找到Tag.class中的PatientName对应的int值常量,便可以将其脱敏。

Attributes attr = new Attributes(...);
attr.remove(Tag.PatientID);
或
attr.remove(0x00100020);

而且,我在Tag.class中也找到了我本次想要脱敏的Tag.
在这里插入图片描述

但是当我采用类似上面的代码,想要去掉这个Tag时,却失败了。

Attributes attr = new Attributes(...);
attr.remove(Tag.SequenceDelimitationItem);
或
attr.remove(0xFFFEE0DD);

这到底是什么原因呢?为什么同样的代码,在这里就不生效了呢。

而且Tag.class这里的定义常量的方式,其实也感觉是有问题的。

public static final int SequenceDelimitationItem = 0xFFFEE0DD;

我们都知道int值,是有大小范围的。那么int的最大值,对应的十六进制的值,是多少呢?

在这里插入图片描述
而上面在定义 SequenceDelimitationItem时,对应的十六进制,已经是超过了0x7FFFFFFF。那么,对应的int值其实已经是一个负数了。这里是我不太理解的地方。

这时陷入了僵局。

转而,我想看看,用python的pydicom提供的脱敏的方法,能不能把这个tag给脱敏掉。

2.2 python -> pydicom

pydicom提供的脱敏的函数,也比较简单。主要是以下几个步骤:

import pydicom
from pydicom.tag import Tag
 
ds = pydicom.dcmread('test.dcm')
tag = Tag(0x00100020)
if tag in ds:
	del ds[tag]

但是同样的代码,在脱敏0xFFFEE0DD时,就又报错了。
在这里插入图片描述
在校验这个tag, 是否属于pydicom的dcm的dataset时,直接返回了False. 而从dataset中,希望取出这个值时,也是报了KeyError的错误。

这时,我意识到了,这个Tag,和其他正常的Tag, 是有区别的。

通过咨询AI, 也确实得到了相应的答复。

在这里插入图片描述
在这里插入图片描述

上面的说法,指出类似: (FFFE, E000), (FFFE, E00D)和(FFFE, E0DD), 这几个Tag, 都是不存在于dataset中的,它们只是一个分割符。用来分割不同层级的Sequence的Tag.

明白了这几个Tag的作用后,我也就不再纠结要专门去脱敏这几个Tag了。而是,我尝试分别把它要分割的那几个Sequence的Tag给脱敏掉。当我把分割符号,前后的Tag都脱敏掉后,再去dump保存后的文件时,这几个分割符,自然也就不存在了。

从下面这幅图中可以看出,(fffe, e0dd)出现了好几次。它其实就是为了分割前后出现的,类型为SQ的Tag的。

(0029, 1140) SQ
(fffe, e0dd) na
(0032, 1060) LO
(0032, 1064) SQ
(fffe, e0dd) na
(0040, 0009) SH
(0040, 0275) SQ
(fffe, e0dd) na
(0400, 0561) SQ
......

在这里插入图片描述
后来,我尝试用gdcmdump, 查看之前的那张待脱敏的图像的Tag, 其实显示还是比较明显的。

可以看到,在gdcmdump解析dicom的tag后,对于这几个分割符,可以很明显得看出它们的位置和作用。
在这里插入图片描述

明白了分割符的作用后。在脱敏时,只需要把它要分割的,VR为SQ类型的tag脱敏掉,那么这个分割符,也就自动没有了。而且分割符,本身也没有任何的标签值,也不包含敏感信息。

3. 总结:

弄了半天,原来和一个分割符,较了好长时间的劲。这还是源于自己对于dicom tag的认识,缺少认识。通过这次脱敏的实现,也补上了这块短板。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

inter_peng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值