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 版本以来可用。
当我读取 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 版本以来可用。