How to generate SOPInstance UID for DICOM file?
Asked Answered
N

4

7

I am developing a system which will be able to create structured report for PACS.

Obviously in order to create a DICOM instance (file containing Report data), I need three UIDs for Study, Series and Instance. StudyUID and SeriesUID must be the same as that of study and series that report is created for. But for SOPInstanceUID, I need to generate new UID.

I have seen getNewSOPInstanceUID method in Pixelmed documentation, but I am not familiar with the Pixelmed source. I need an algorithm or Python source.

Nievesniflheim answered 24/4, 2012 at 10:5 Comment(1)
You'll need more than just an algorithm. DICOM UIDs must be globally unique and, therefore, you'll have to register with one of the designated authorities to obtain the root stem that will be used for all of the UIDs that you generate.Lacuna
C
-1

I would really suggest you go away from implementing it yourself. Most language do provide a UUID library these days, do not reinvent the wheel. Esp. if you are going to write code to extract MAC adress, this can be very complex writing it in portable C.

UUID do not exactly fit the DICOM definition, so you need to register your own Organisation Root UID, then simply pad with a generated UUID which bring spatial and time uniqueness condition.

YOUR_ORG_ROOT.CONVERTED_UUID

Pay attention that you have 64 bytes (that's plenty already, see here) for storage in Value Representation UI:

  • Convert Hexadecimal notation of UUID to VR: UI definition ([0-9.]+)
  • Trim with extreme care (you may introduce redundancy during this operation)
  • Choose a short Org Root
  • Pad with \0 (0 binary) if needed.

Finally since you are using python, use uuid lib python-uuid.


The above should be considered an alternate implementation to what is officially defined in the standard:

When converting directly a UUID to a UID, one must use the "2.25." root.

Crompton answered 7/1, 2013 at 12:10 Comment(1)
The advice to create not your own UUID algorithm is very sound. The steps to convert a UUID to a DICOM UID are incorrect. The DICOM standard has specific rules for that conversion (see part 5, paragraph b.2)Tabaret
T
12

There are 2 ways in DICOM to create UIDs. One based on a registered UID root and one based on a UUID. The later method was added to the DICOM standard with CP-1156 in 2012. UIDs for things like Study UID, Series UID, SOP Instance UID can be created by converting a UUID to a DICOM UID.

Most programming languages have build in support to create a UUID. The sample code code below creates a valid DICOM UID in C# based on a GUID value.

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

The following method does the same but is about 5 times faster:

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);
}
Tabaret answered 4/1, 2013 at 22:20 Comment(3)
While I love the simplicity of this answer, it should be noticed that you are restricting (so to say) yourself to only the 128bits part of the UUID. While DICOM UID provide a much wider range...Crompton
The DICOM standard requires that if an UUID is used for a DICOM UID the format as specified in Part 5, paragraph B.2 is used. This makes sense, a 128 bit UUID is already statically unique (see Wikipedia), and adding more bytes doesn't make it significantly more unique. Adding extra bytes is also problematic for other systems that want to extract the UUID part from the DICOM UIDs from DICOM objects they receive.Tabaret
@VictorDerks: I have referred first block of code in my other answer here. The core logic is same; just some improvements and explanation added.Chop
C
8

Refer this answer for more details about DICOM UID.

A] Increment the counters [Not Recommended]

One simple logic is to get your SeriesInstanceUID and increment it by 1. So say your SeriesInstanceUID is "1.1.1.1.1" then your SOPInstanceUID may be "1.1.1.1.2" or "1.1.1.1.1.1".

Problems:

  • When the instance is deleted and next instance is created, the earlier counter should not be used.
  • In multi-threaded environment, enough care should be taken.
  • Does not guarantee uniqueness across different systems/applications.

B] Date Time [Not Recommended]

Other technique generally used is to append time stamp (with ticks) to organization root.

Problems:

  • Multi-threaded environment is an issue.
  • System clock may go off.
  • Uniqueness across different systems/applications cannot be guaranteed.

C] More Complex [RECOMMENDED]

1.2.840.xxxxx.30.152.99999.235.20.100.yyyyMMddHHmmss.zzzzzz

Where:

1.2.840.xxxxx: Organization Root
30: Application ID
152: Application Version
99999: Installation/Location ID
235: Study ID
20: Series Number
100: Image Number
yyyyMMddHHmmss: Date Time
zzzzzz: Thread safe counter/Random Number

Problems:

  • Algorithm may fail in case system clock goes off; this is protected by thread safe counter/random number further. Remote possibility; need to take little care.

D] UUID Derived UID [RECOMMENDED]

UID may be generated from the root "2.25." followed by a decimal representation of a Universally Unique Identifier (UUID).

Problems:

  • This may be appropriate for dynamically created UIDs, such as SOP Instance UIDs, but is not appropriate for UIDs determined during design, such as private SOP Class or Transfer Syntax UIDs, or Implementation Class UIDs.
  • UID is restricted to only 128 bits. DICOM UID support wider range.
Chop answered 20/9, 2017 at 8:12 Comment(1)
The DICOM standard allows UUID derived UIDs to be used for "design" UIDs like Transfer Syntax, but using the "organization root" format is preferred as it makes it much easier to detect who designed that new transfer syntax. Software engineers need sometime to create such a new UID, running application only need dynamically created UIDsTabaret
M
2

According to the DICOM standard (PS 3.5-2011 Page 61), you need an orgroot and a suffix. Examples can be found here (PS 3.5-2011 Page 83).

Also do not forget that UI Fields have to be padded (if they do not have an even length) with '\0' bytes and not with spaces.

I would suggest to create the UID like this:

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

Beware that the limit is 64 chars!

Mabuse answered 25/4, 2012 at 12:45 Comment(1)
You are missing the spatial condition before the temporally uniqueness, see RFC 4122. Should be more like: YOUR_ORGROOT.SPATIAL.TIMECrompton
C
-1

I would really suggest you go away from implementing it yourself. Most language do provide a UUID library these days, do not reinvent the wheel. Esp. if you are going to write code to extract MAC adress, this can be very complex writing it in portable C.

UUID do not exactly fit the DICOM definition, so you need to register your own Organisation Root UID, then simply pad with a generated UUID which bring spatial and time uniqueness condition.

YOUR_ORG_ROOT.CONVERTED_UUID

Pay attention that you have 64 bytes (that's plenty already, see here) for storage in Value Representation UI:

  • Convert Hexadecimal notation of UUID to VR: UI definition ([0-9.]+)
  • Trim with extreme care (you may introduce redundancy during this operation)
  • Choose a short Org Root
  • Pad with \0 (0 binary) if needed.

Finally since you are using python, use uuid lib python-uuid.


The above should be considered an alternate implementation to what is officially defined in the standard:

When converting directly a UUID to a UID, one must use the "2.25." root.

Crompton answered 7/1, 2013 at 12:10 Comment(1)
The advice to create not your own UUID algorithm is very sound. The steps to convert a UUID to a DICOM UID are incorrect. The DICOM standard has specific rules for that conversion (see part 5, paragraph b.2)Tabaret

© 2022 - 2024 — McMap. All rights reserved.