【问题标题】:How to generate SOPInstance UID for DICOM file?如何为 DICOM 文件生成 SOPInstance UID?
【发布时间】:2012-05-04 23:09:07
【问题描述】:

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

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

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

【问题讨论】:

  • 您需要的不仅仅是算法。 DICOM UID 必须是全球唯一的,因此,您必须向指定机构之一注册,以获得将用于您生成的所有 UID 的根茎。

标签: python uuid uniqueidentifier dicom


【解决方案1】:

有关 DICOM UID 的更多详细信息,请参阅this 答案。

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

一个简单的逻辑是获取您的 SeriesInstanceUID 并将其递增 1。 假设您的 SeriesInstanceUID 是“1.1.1.1.1”,那么您的 SOPInstanceUID 可能是“1.1.1.1.2”或“1.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: strong> 图像编号
yyyyMMddHHmmss: 日期时间
zzzzzz: 线程安全计数器/随机数

问题:

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

D] UUID 派生的 UID [推荐]

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

问题:

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

【讨论】:

  • DICOM 标准允许将 UUID 派生的 UID 用于“设计” UID,如传输语法,但首选使用“组织根”格式,因为它可以更容易地检测是谁设计了新的传输句法。软件工程师需要一些时间来创建这样一个新的 UID,运行应用程序只需要动态创建的 UID
【解决方案2】:

我真的建议您远离,不要自己实现它。现在大多数语言都提供了一个 UUID 库,不要重新发明轮子。特别是。如果您要编写代码来提取 MAC 地址,使用 portable C 编写它可能会非常复杂。

UUID 不完全符合 DICOM 定义,因此您需要注册自己的 Organization Root 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”。根。

【讨论】:

  • 不创建自己的 UUID 算法的建议非常合理。将 UUID 转换为 DICOM UID 的步骤不正确。 DICOM 标准对该转换有特定的规则(参见第 5 部分,第 b.2 段)
【解决方案3】:

DICOM 中有两种创建 UID 的方法。一种基于已注册的 UID 根,另一种基于 UUID。后一种方法于 2012 年通过 CP-1156 添加到 DICOM 标准中。可以通过将 UUID 转换为 DICOM UID 来创建诸如研究 UID、系列 UID、SOP 实例 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 的 128 位部分。虽然 DICOM UID 提供了更广泛的范围......
  • DICOM 标准要求,如果 UUID 用于 DICOM UID,则使用第 5 部分 B.2 段中指定的格式。这是有道理的,一个 128 位的 UUID 已经是静态唯一的(参见 Wikipedia),并且添加更多字节并不会使其更加独特。对于希望从接收到的 DICOM 对象的 DICOM UID 中提取 UUID 部分的其他系统来说,添加额外的字节也是有问题的。
  • @VictorDerks:我在另一个答案here 中提到了第一块代码。核心逻辑相同;只是添加了一些改进和解释。
【解决方案4】:

根据DICOM standard(PS 3.5-2011 第 61 页),您需要一个 orgroot 和一个后缀。可以在此处找到示例(PS 3.5-2011 第 83 页)。

另外不要忘记,UI 字段必须用 '\0' 字节而不是空格填充(如果它们没有偶数长度)。

我建议像这样创建 UID:

YOUR_ORGROOT.Year.Month.Day.Hour.Minute.Second.Milliseconds.StaticCounter

注意限制为 64 个字符!

【讨论】:

  • 您在时间唯一性之前缺少空间条件,请参阅 RFC 4122。应该更像:YOUR_ORGROOT.SPATIAL.TIME
猜你喜欢
  • 2018-02-28
  • 1970-01-01
  • 2016-10-13
  • 2020-01-20
  • 2015-12-17
  • 2019-06-15
  • 1970-01-01
  • 2016-02-13
  • 1970-01-01
相关资源
最近更新 更多