Pydicom 私人标签显示为 'UN'

Pydicom private tags showing up as 'UN'

当我读取 dicom 文件时,所有私有标签都显示为 'UN',而不是它们应有的任何内容。

import pydicom
filename = 'H:\Fuji.dcm'
ds = pydicom.dcmread(filename)
print(ds)

输出为:

...
(0009, 0010) Private Creator                     LO: 'FDMS 1.0'
(0009, 1005) [Image UID]                         UN: b'\x1d\xa6h\x12\x08\x07pZ\x0f9\x0e\xc2'
(0009, 1006) [Route Image UID]                   UN: b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
(0009, 1008) [Image Display Information Version  UN: b'\x00\x00\x00\x00'
(0009, 1009) [Patient Information Version No.]   UN: b'\x00\x00\x00\x00'
(0009, 100c) [Film UID]                          UN: b'\x1d\xa6h\x12\x08\x07pZ\x0f9\x0e\xc2'
(0009, 1010) [Exposure Unit Type Code]           UN: b'F3'
(0009, 1080) [Kanji Hospital Name]               UN: None
(0009, 1090) [Distribution Code]                 UN: b'MAINPACS'
(0009, 10f0) [Blackening Process Flag]           UN: b'01'
(0009, 10f1) [Processing Information Flag]       UN: b'0001'
(0009, 10f2) Private tag data                    UN: b'01'
(0009, 10f3) Private tag data                    UN: b'01'
(0009, 10f4) Private tag data                    UN: b'01'
...

如果我尝试手动添加它们,这不会改变:

pydicom.datadict.add_private_dict_entries('FDMS 1.0', 
                                          {0x00090005:('OW','1','Image UID'),
                                           0x00090006:('OW','1','Route Image UID'),
                                           0x00090008:('UL','1','Image Display Information Version No.'),
                                           0x00090009:('UL','1','Patient Information Version No.'),
                                           0x0009000c:('OW','1','Film UID'),
                                           0x00090010:('CS','1','Exposure Unit Type Code'),
                                           0x00090080:('LO','1','Kanji Hospital Name'),
                                           0x00090090:('ST','1','Distribution Code'),
                                           0x000900F0:('CS','1','Blackening Process Flag'),
                                           0x000900F1:('ST','1','Processing Information Flag'),
                                           0x000900F2:('CS','1','Normalization Flag'),
                                           0x000900F3:('CS','1','Tone characteristic'),
                                           0x000900F4:('CS','1','Window Value Fixed Flag'),
                                           })
print(ds)

它正确地拾取了缺失标签的描述,但仍然不会从 UN 更改它们的 VR:

...
(0009, 0010) Private Creator                     LO: 'FDMS 1.0'
(0009, 1005) [Image UID]                         UN: b'\x1d\xa6h\x12\x08\x07pZ\x0f9\x0e\xc2'
(0009, 1006) [Route Image UID]                   UN: b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
(0009, 1008) [Image Display Information Version  UN: b'\x00\x00\x00\x00'
(0009, 1009) [Patient Information Version No.]   UN: b'\x00\x00\x00\x00'
(0009, 100c) [Film UID]                          UN: b'\x1d\xa6h\x12\x08\x07pZ\x0f9\x0e\xc2'
(0009, 1010) [Exposure Unit Type Code]           UN: b'F3'
(0009, 1080) [Kanji Hospital Name]               UN: None
(0009, 1090) [Distribution Code]                 UN: b'MAINPACS'
(0009, 10f0) [Blackening Process Flag]           UN: b'01'
(0009, 10f1) [Processing Information Flag]       UN: b'0001'
(0009, 10f2) [Normalization Flag]                UN: b'01'
(0009, 10f3) [Tone characteristic]               UN: b'01'
(0009, 10f4) [Window Value Fixed Flag]           UN: b'01'
...

这似乎是我尝试过的所有临床 dicom 文件的一致行为,无论我在阅读 dicom 文件之前还是之后添加条目都没有区别。

我在这个例子中使用的文件在这里:

https://drive.google.com/file/d/1SxDXG7cQQZQFluq88zPXUInMI_-6SsKK/view?usp=sharing

在此先感谢您提供的任何帮助。

对于未来的任何人:

我将下面来自 MrBean Bremen 的代码与来自 pydicom.values.convert_values 的一些代码结合起来,得到以下函数来代替 dcmread:

def dcmread_convert_private(filename):
    ds = pydicom.dcmread(filename)
    for e in ds:
        if e.tag.is_private and e.VR == 'UN':
            try:
                index = (e.tag.element >> 12) - 1
                if index >= 0:
                    private_creators = ds.private_creators(e.tag.group)
                    if len(private_creators) > index:
                        private_creator = private_creators[index]
                        e.VR = pydicom.datadict.private_dictionary_VR(e.tag, private_creator)
                        # Following code taken from pydicom.values.convert_value
                        if e.value:
                            if isinstance(pydicom.values.converters[e.VR], tuple):
                                converter, num_format = pydicom.values.converters[e.VR]
                            else:
                                converter = pydicom.values.converters[e.VR]
                                num_format = None
                            byte_string = e.value
                            is_little_endian = ds.is_little_endian
                            is_implicit_VR = ds.is_implicit_VR
                            if e.VR in pydicom.charset.text_VRs or e.VR == 'PN':
                                e.value = converter(byte_string)
                            elif e.VR != "SQ":
                                e.value = converter(byte_string,
                                                  is_little_endian,
                                                  num_format)
                            else:
                                e.value = convert_SQ(byte_string,
                                                   is_implicit_VR,
                                                   is_little_endian,
                                                   e.value)
            except KeyError:
                pass
    return ds

我只在几个 dicom 文件上对此进行了测试,因此可能存在未正确处理的情况。如果我遇到任何问题,我会尽量记得在修复后返回这里更新。

问题是标签已经写成 UN 在文件中,并且保存为 Explicit VR。我猜它最初是作为隐式 VR 编写的,后来转换为显式 VR - 在此转换过程中,所有未知的私有标签都得到 UN 作为 VR。

注册私人标签并重新读取文件的情况在 pydicom 中不处理 - UN 的情况仅针对非私人标签处理。所以你运气不好。

不过,我认为这是可以添加到 pydicom 的东西 - 我不确定这是否会是性能方面的问题,但提交相应的问题是有意义的(你可以这样做你自己,或者如果你愿意,我可以做)。

这是一个快速而粗略的实现,用于在读取数据集后转换标签:

from pydicom import dcmread
from pydicom.datadict import private_dictionary_VR

ds = dcmread('xxx.dcm'))
for e in ds:
    if e.tag.is_private and e.VR == 'UN':
        try:
            index = (e.tag.element >> 12) - 1
            if index >= 0:
                private_creators = ds.private_creators(e.tag.group)
                if len(private_creators) > index:
                    private_creator = private_creators[index]
                    e.VR = private_dictionary_VR(e.tag, private_creator)
        except KeyError:
            pass
print(ds)

更新:
这是在 pydicom issue 中处理的,并且自 pydicom 2.2 版本以来可用。