python 如何为DICOM文件生成SOPInstance UID?

toe95027  于 2023-02-07  发布在  Python
关注(0)|答案(5)|浏览(398)

我正在开发一个系统,将能够创建PACS的结构化报告。
显然,为了创建一个DICOM示例(包含报告数据的文件),我需要三个UID用于案例、系列和示例。StudyUID和SeriesUID必须与创建报告的案例和系列的UID相同。但对于SOPInstanceUID,我需要生成新的UID。
我在Pixelmed文档中看到过getNewSOPInstanceUID方法,但我对Pixelmed源代码不熟悉,我需要一个算法或Python源代码。

r8xiu3jd

r8xiu3jd1#

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);
}
rdrgkggo

rdrgkggo2#

    • 有关DICOM UID的更多详细信息,请参阅this答案。**
    • A]递增计数器[不推荐]**

一个简单的逻辑是获取您的序列示例UID并将其递增1。因此,假设您的序列示例UID是"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:**研究编号
    • 20:**序列号
    • 100:**图像编号
    • 年月日小时分钟秒:**日期时间
    • zzzzzz:**线程安全计数器/随机数

问题:

  • 系统时钟关闭时算法可能失效;这由线程安全计数器/随机数进一步保护。不需要太小心。
    • D] UUID派生的UID [推荐]**

UID可以从根"2.25."后面跟随通用唯一标识符(UUID)的十进制表示来生成。
问题:

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

cbwuti443#

根据DICOM standard(PS3.5 -2011第61页),你需要一个orgroot和一个后缀。示例可以在这里找到(PS3.5 -2011第83页)。
另外,不要忘记UI字段必须用“\0”字节填充(如果它们的长度不是偶数),而不是用空格填充。
我建议像这样创建UID:
YOUR_ORGROOT.年.月.日.时.分.秒.毫秒.静态计数器
请注意,限制为64个字符!

of1yzvn4

of1yzvn44#

DICOM UIDs这些标识符共同用于显示有关生成设备、患者、单个会议和构成研究的文件的不同信息。继续,研究中的每个图像包含几个不同的UID,用于将单个图像链接到系列的其余图像、检查和整个患者会议(层次结构为:患者〉研究〉系列〉图像)。作为该过程的一部分生成的UID必须是全球唯一的,并且存在许多发布登记,其通过根据需要将批次分配给制造商和个人或位置来寻求避免重复。
为DICOM服务生成的所有UID均从第一个数字1.2.840.10008[...]开始,以便在更广泛的网络流量中轻松识别。

nnt7mjpx

nnt7mjpx5#

我真的建议你不要自己实现它。现在大多数语言都提供UUID库,不要重新发明轮子。特别是如果你要写代码来提取MAC地址,用可移植C写它会很复杂。
UUID并不完全符合DICOM定义,因此您需要注册自己的组织根UID,然后简单地填充生成的UUID,这将带来空间和时间唯一性条件。

YOUR_ORG_ROOT.CONVERTED_UUID

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

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

最后,因为你使用的是python,所以使用uuid lib python-uuid
上述内容应被视为标准中正式定义内容的替代实现:

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

相关问题