如何为DICOM文件生成SOPInstance UID?

2024-04-25 20:49:18 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在开发一个能够为PACS创建结构化报表的系统。

显然,为了创建一个DICOM实例(包含报表数据的文件),我需要三个uid用于研究、系列和实例。StudyUID和SeriesUID必须与为其创建报表的study和SeriesUID相同。但是对于SOPInstanceUID,我需要生成新的UID。

我在Pixelmed文档中见过getNewSOPInstanceUID方法,但我不熟悉Pixelmed源代码。我需要一个算法或Python源代码。


Tags: 文件数据实例uid报表源代码系统pacs
3条回答

Refer this answer for more details about DICOM UID.

A]递增计数器[不推荐]

一个简单的逻辑是获取serieinstanceuid并将其递增1。 因此,假设您的serieInstanceUid是“1.1.1.1.1”,那么您的SOPInstanceUID可能是“1.1.1.1.2”或“1.1.1.1.1”。

问题:

  • 删除实例并创建下一个实例时,不应使用前面的计数器。
  • 在多线程环境中,应该足够小心。
  • 不保证不同系统/应用程序之间的唯一性。

B]日期时间[不推荐]

通常使用的其他技术是将时间戳(带有记号)附加到组织根目录。

问题:

  • 多线程环境是一个问题。
  • 系统时钟可能会关闭。
  • 无法保证不同系统/应用程序之间的唯一性。

C]更复杂[推荐]

1.2.840.xxxxx.30.152.99999.235.20.100.yyyyMMddHHmmss.zzzzzz

其中:

1.2.840.xxxxx:组织根
30:应用程序ID
152:应用程序版本
99999:安装/位置ID
235:研究ID
20:序列号
100:图像编号
yyyymmddhhmms:日期时间
zzzzzz:线程安全计数器/随机数

问题:

  • 如果系统时钟关闭,算法可能会失败;这将进一步受到线程安全计数器/随机数的保护。可能性很小;不需要多加注意。

D]UUID派生的UID[推荐]

UID可以从根“2.25”生成,后跟通用唯一标识符(UUID)的十进制表示。

问题:

  • 这可能适用于动态创建的uid,例如SOP实例uid,但不适用于在设计期间确定的uid,例如私有SOP类或传输语法uid,或实现类uid。
  • UID仅限于128位。DICOM UID支持更广泛的范围。

DICOM中有两种创建uid的方法。一个基于注册的UID根,另一个基于UUID。后一种方法于2012年与CP-1156一起添加到DICOM标准中。可以通过将UUID转换为DICOM UID来创建诸如Study UID、Series UID、SOP Instance UID之类的UID。

大多数编程语言都内置了创建UUID的支持。下面的示例代码基于GUID值在C中创建一个有效的DICOM UID。

public static string GuidToUidStringUsingStringAndParse(Guid value)
{
    var guidBytes = string.Format("0{0:N}", value);
    var bigInteger = BigInteger.Parse(guidBytes, NumberStyles.HexNumber);
    return string.Format(CultureInfo.InvariantCulture, "2.25.{0}", bigInteger);
}

以下方法的速度与此相同,但大约快5倍:

public static string ConvertGuidToUuidInteger(ref Guid value)
{
    // ISO/IEC 9834-8, paragraph 6.3 (referenced by DICOM PS 3.5, B.2) defines how
    // to convert a UUID to a single integer value that can be converted back into a UUID.

    // The Guid.ToByteArray Method returns the array in a strange order (see .NET docs),
    // BigInteger expects the input array in little endian order.
    // The last byte controls the sign, add an additional zero to ensure
    // the array is parsed as a positive number.
    var octets = value.ToByteArray();
    var littleEndianOrder = new byte[]
    { octets[15], octets[14], octets[13], octets[12], octets[11], octets[10], octets[9], octets[8],
        octets[6], octets[7], octets[4], octets[5], octets[0], octets[1], octets[2], octets[3], 0 };

    return "2.25." + new BigInteger(littleEndianOrder).ToString(CultureInfo.InvariantCulture);
}

我真的建议你不要自己去实现它。如今,大多数语言都提供了UUID库,而不是重新发明轮子。特别是,如果要编写代码来提取MAC地址,用portableC编写可能会非常复杂

UUID不完全符合DICOM定义,因此您需要注册自己的组织根UID,然后简单地填充生成的UUID,该UUID带来空间和时间唯一性条件。

YOUR_ORG_ROOT.CONVERTED_UUID

注意,在值表示UI中有64个字节(已经足够了,请参见here)用于存储:

  • 将UUID的十六进制表示法转换为VR:UI定义([0-9.]+)
  • 极其小心地修剪(在此操作过程中可能会引入冗余)
  • 选择一个短的Org Root
  • 如果需要,用\0(0二进制)填充。

最后,因为您使用的是python,所以请使用uuid libpython-uuid


上述内容应视为标准中正式定义的替代实施:

当直接将UUID转换为UID时,必须使用“2.25.”根。

相关问题 更多 >