Friday, June 23, 2023

Introduction to DICOM - Chapter 3 - DICOM Elements

Chapter 3 – DICOM Elements

Let’s start with a useful example. Suppose you are a dermatologist and that you use your Smartphone digital camera to record and track patients’ skin condition. You practice a simple procedure that is basically this:

1. Take a photo

2. Send it to yourself by email

3. Open the email on your laptop and save the picture in a folder having the patient name.

As programmers, we don’t have to talk much about the flows of this practice but for a small, one doctor clinic, this might just work.

In this lesson, we’ll take the JPEG image and DICOMIZE it. When we DICOMIZE an Image we wrap the image in a DICOM envelope and add important data that is required by the DICOM standard in order to enable all DICOM enabled applications to read and display the image correctly. It’s true that non DICOM application can display the JPEG image just as it is now without DICOMIZING but that’s another story.


We will use MODALIZER-SDK DICOM Toolkit to convert the image to a DICOM object. Then we’ll ‘dump’ the content of the DICOM object into a text file in order to see how DICOM objects are structured.

To convert to DICOM using RZDCX we’ll use the following three lines of C# code:

        private void Convert()
        {
            DCXOBJ o = new DCXOBJ();
            string jpegImage = "my_image.jpg";
            o.SetJpegFrames(jpegImage);
        }

Now let’s see what we have in the file after that by adding a small dump to text file so our function now looks like this:

        private void Convert()
        {
            DCXOBJ o = new DCXOBJ();
            string jpegImage = "my_image.jpg";
            o.SetJpegFrames(jpegImage);
            o.Dump("my_image.txt");
        }


If we now look at the content of the file my_image.txt we'll see this:

# Dicom-Data-Set
# Used TransferSyntax: UnknownTransferSyntax
(0008,0016) UI =SecondaryCaptureImageStorage # 26, 1 SOPClassUID
(0028,0002) US 3 # 2, 1 SamplesPerPixel
(0028,0004) CS [YBR_FULL_422] # 12, 1 PhotometricInterpretation
(0028,0006) US 0 # 2, 1 PlanarConfiguration
(0028,0010) US 96 # 2, 1 Rows
(0028,0011) US 372 # 2, 1 Columns
(0028,0100) US 8 # 2, 1 BitsAllocated
(0028,0101) US 8 # 2, 1 BitsStored
(0028,0102) US 7 # 2, 1 HighBit
(0028,0103) US 0 # 2, 1 PixelRepresentation
(0028,2110) CS [01] # 2, 1 LossyImageCompression
(0028,2114) CS [ISO_10918_1] # 12, 1 LossyImageCompressionMethod
(7fe0,0010) OB (PixelSequence #=2) # u/l, 1 PixelData
  (fffe,e000) pi (no value available) # 0, 1 Item
  (fffe,e000) pi ff\d8\ff\db\00\43\00\08\06\06\07\06\05\08\07\07\07\09\09\08\0a\0c... # 9624, 1 Item
(fffe,e0dd) na (SequenceDelimitationItem) # 0, 0 SequenceDelimitationItem

Let’s go over this dump and see what’s in it. The lines starting with a hash (#) are comments and we’ll ignore them.


DICOM Elements

A DICOM object is comprised of DICOM elements or DICOM attributes. Every line in the above dump represents one element.
Every DICOM Element has a Tag, a Data Type called VR (acronym for Value Representation), Length and Value. In the dump above the lines starts with the tag number (gggg,eeee), then the VR Code, then the value (strings are printed in square brackets) and then a hash sign (#) followed by the element value length, a comma, then Value multiplicity (which we'll talk about later) and the tag name. The tag name and multiplicity are add by the dump method. The way DICOM encodes elements is shown in this drawing taken from the DICOM standard, chapter 5.
Illustration of DICOM element encoding in a DICOM data stream
Image takes from the DICOM standard, Chapter 5.
Tags
Every DICOM element has a Tag that uniquely defines the element and its properties, much like a bar code defines a product in the supermarket. The DICOM tag is comprised of two short numbers called Group and Element. DICOM Tags that are related to one another sometimes have the same group. In our example you can see many elements from group 0028. This is the Image group. These are attributes of the image and are used to describe the image properties. For example (0028,0010) is Rows element and it is the height of the image. (0028,0011) is the Columns and it is the width of the image in pixels. There are more elements of the image group in our example and we’ll describe them in detail when we talk about interpreting and displaying DICOM Images.
Value Representation
The VR is represented as two character code. The VR defines the data type of the element. In our example you can see UI for Unique identifier, US for Unsigned Short, CS for Coded String and OB for Other Byte i.e. a byte stream.
Because every element has a Tag, the tag implicitly defines the VR. For example the Rows element (Tag 0028,0010) is always US (Unsigned Short). This is why the VR is usually redundant and can be omitted. However, the common practice and IHE recommendation is to explicitly state the VR when serializing DICOM objects into files or into network buffers. We’ll talk more about that when we discuss Implicit and Explicit Transfer Syntax.

Value Length
Because DICOM is a binary protocol (in contrast to textual protocols such as html and xml) elements have length. DICOM elements length are always even. Even if the element’s value is a single character string like Patient Sex (0010,0040) that is either ‘M’ for Male or ‘F’ for Female or ‘O’ for Other, the element length should be 2 and the value will be padded by a space (ASCII 0x20). String types (like CS and UI) are padded by space and binary types like US are padded by null 0x0.

Summary
  • DICOM Elements are the building blocks of the DICOM standards. They are used in DICOM files and in network communication.
  • Every element has a unique Tag that specifies what’s in the element and its data type.
  • DICOM Elements are typed. The DICOM data types are called VR.
  • Every Element has even length, even if it's value length is odd. Strings are padded with a space and binary data with a null.
Adding Elements to an Object
We conclude this example with a short code snippet showing how to add elements to a DICOM object using RZDCX.
RZDCX takes care of the details for you, so you simply create a new element, initialize it with the Tag and set the value. Here's the code:



            DCXOBJ o = new DCXOBJ();
            DCXELM e = new DCXELM();
            // Manufecturer
            e.Init((int)DICOM_TAGS_ENUM.Manufacturer);
            e.Value = "RZ - Software Services"
            o.insertElement(e);

In the next chapter we'll add more data elements to the DICOM object we've created to make it a valid DICOM object and then save it to a file and we'll discuss the differences between DICOM objects and DICOM files.

38 comments:

  1. Hi Roni,

    A small correction in the diagram of the dump. The Value Representation(VR) is showing as VM.

    any way this is awesome.

    Thanks

    ReplyDelete
    Replies
    1. Sekhar is right. I guess you need to read again

      Delete
    2. +1 , the image dicom-elements-explained.png says "US", next to the Tag, is the VM instead of the VR.

      Delete
    3. It has been pointed out in 2012. but this website is great if someone wants to know about Dicom. Its the best document available on internet.

      Delete
  2. Excellent work.

    I'm trying to test it with Delphi but after importing the TLB file, I can not insert elements (DCXELM) in DICOM objects (DCXOBJ) with the method "insertelement". Surely the problem is the file that I generated in Delphi, and not whether to switch to C #, I understand that problems will not.

    Regards.

    ReplyDelete
  3. Excellent work.

    I'm trying to test it with Delphi but after importing the TLB file, I can not insert elements (DCXELM) in DICOM objects (DCXOBJ) with the method "insertelement". Surely the problem is the file that I generated in Delphi, and not whether to switch to C #, I understand that problems will not.

    Regards.

    ReplyDelete
  4. excellent work.

    I'm trying to test it with Delphi but after importing the TLB file, I can not insert elements (DCXELM) in DICOM objects (DCXOBJ) with the method "insertelement". Surely the problem is the file that I generated in Delphi, and not whether to switch to C #, I understand that problems will not.

    regards

    ReplyDelete
    Replies
    1. Hi Miguel,
      Have you registered the dll using regsvr32?
      Can you post the exact error message that you get?
      Roni

      Delete
  5. I created the new element and the type was LO which wasn't discussed. Also I'm about confused by groups, are those set in stone? Meaning does Group 28 always have to do with the image attributes?

    ReplyDelete
  6. This is a question I got from Pedro that was deleted by mistake:

    Hello Mate! Thank you a lot for your help! Maybe you can explain why some elements dont respect the structure though. For instance, in group 2 header:
    44 49 43 4d 02 00 00 00 55 4c 04 00 c0 00 00 00 02 00 01 00 4f 42 00 00 02 00 00 00 00 01 02 00 02 00 55 49 1a 00 31 2e 32 2e 38 34 30 2e 31 30 30 30 38 2e 35 2e 31 2e 34 2e 31 2e 31 2e 31 00
    This happens in almost all DICOM files I've seen. after the "DICM" you get a (0002,0000) with VR UL (55,4C) and length 4. Then the element right after is a (0002,0001) with 0 length and then we are back to a element (0002,0000) with a weird VR (00 01) and no length information. It skips to element (0002,0002)?! I dont get this.

    ReplyDelete
    Replies
    1. Hi Pedro,
      You missed a little thing. The element (0002,0001) of type OB. This VR is encoded with 4bytes. The VR code is OB and then two 0x0 bytes. If you read it this way, everything will fall into place. The OB is not alone. OB, OW and UN all have 4 bytes VR code.
      Roni

      Delete
  7. you have a mistake in first picture. VR instead of VM. Thanks for turorial

    ReplyDelete
    Replies
    1. agreed, LOVE this tutorial, but the red VM with the yellow background in the first image should be VR. Confused me at first glance.

      Delete
  8. i have registered rzdcx.dll using segsvr32.exe and registered properly but when i add reference in visual studio 2012 that time i got error "A reference to 'rzdcx 1.0 Type Library' could not be added please give solution thanks.

    ReplyDelete
  9. excellent work.
    Hi Roni

    i have a wonder and hope to receive the your answers. That is:
    Why the UID_LittleEndianImplicitTransferSyntax is defined as : 1.2.840.10008.1.2
    what is the meaning of that string or is it just convention?
    and for for other syntaxs.

    manythanks,

    ReplyDelete
    Replies
    1. It has no meaning. Its just an id

      Delete
    2. Hi Roni,
      In your above explanation of "Value Length" section, you have written "String types (like CS and UI) are padded by space and binary types like US are padded by null 0x0."

      But for "UI" VR you should be padding Null character instead of space. Below Link is for your reference.
      "http://medical.nema.org/dicom/2013/output/chtml/part05/sect_6.2.html".

      Delete

  10. hello
    First of all I congratulate the creator of this product, as far as I could read is excellent, now I find myself trying to implement

    I downloaded the library rzdcxLib this day, the add in my project.

    I'm trying to replicate the lessons in chapter 3, but I can not use the following commands:
    1 - o.SetJpegFrames (jpegImage);
    This function no longer exists, is perhaps for some dll update.
    What would be the new name for this line
    2 - o.Dump ("my_image.txt");
    The error I get is "Attempted to access an unloaded AppDomain (Exception from HRESULT: 0x80131014)." It may be due to the number one problem, but I'm not sure.

    I would appreciate an answer
    greetings
    Jacqueline

    ReplyDelete
    Replies
    1. Hi J.
      I think you did not regsvr32 rzdcx.dll.
      It is a COM object, what makes it useful from almost any programming tool for windows.
      Roni

      Delete
    2. Hello rony
      I was very careful to follow the steps in the tutorial and I am 100% sure that if you register the library. In my application I declare recognizes when DCXOBJ type objects.

      I can compile the examples have the product, but there are some variations eg;
      - The PatientName property does not exist, but if there PatientsName.
      - The function does not exist SetBMPFrames
      They are sure things that were updated versions of the dll, but remained in the examples of the page
      Could you help me with some functions please:
      O = new DCXOBJ DCXOBJ ();
      1 - o.SetJpegFrames (jpegImage);
      2 - o.Dump ("my_image.txt");
      3 - o.SetBMPFrames ("my_image.bmp")

      Thank you very much for the response and future aid

      Delete
    3. Dear Jacqueline,
      We have tested this exact code and it works perfectly. We used the latest rzdcx 2.0.5.4
      Note that if you want to create a multi-frame image you should call either SetBMPFrames or SetJpegFrames once with filenames separated by ;
      Roni

      Delete
    4. Hello
      I wanted to thank you for your help, I wanted to let you know that the problem was that he was not using your latest version, in case someone needs to put it here
      http://downloads.roniza.com/downloads/rzdcx/2.0.5.4/
      Thank you

      Delete
  11. This is the clearest presentation of DICOM I've seen so far! Thanks!

    ReplyDelete
  12. Hi Roni,
    This is a wonderful Dicom knowledge base, very useful for me.

    I'm a student and I want to design a Dicom Parser as a part of a project i am into.

    Can you please point me to some knowledge base for taking a Dicom file and converting it to text? I don't know where to begin, and i didn't quite figured out how to approach this.

    thanks

    ReplyDelete
  13. Thank you!!! You saved my school assigment with this chapter!

    ReplyDelete
  14. I am so confused, in the picture it says that after the tag is the VR. In the example this value is US (Unsigned short...) but it is annotated as a VM. VM is incorrect, it should have been annotated (circled in RED) as a VR?

    ReplyDelete
  15. Hello, This is excellent stuff, thank you !

    One question though, the Image Width element (or No. of columns):
    (0028,0011) US 372 # 2, 1 Columns
    How can it have a Value Length of 2?
    Given that its a 3 digit value and elements value lengths are always even should it not be 4?

    Thanks for this wonderful resource.

    ReplyDelete
    Replies
    1. Well,the value length is 2 because its encoded as an Unsigned Short value, (Word). Unlike XML, JSON and even HL7 that are encoded as text, DICOM is binary. The Value Representation is US (Unsigned Short) which is two bytes and can take values in the range [0, 65535].

      Delete
  16. First of all i would like to thank you for this tutorial.
    I man very new in dicom image processing Please, if i want to read the dicom image information, for example the number of row or the patient name, how to do that?
    Thanks in advance.

    ReplyDelete
    Replies
    1. This comment has been removed by the author.

      Delete
  17. I am reading a DICOM file that has nested elements within an SQ element. Can't quite figure out how to iterate through the sub-elements. Can't set a new object to the element to get an iterator. Can your point me in the right direction? Thanks!

    ReplyDelete
  18. I can't load the .tlb file into the project. I have tried adding it as a reference, but shows an error. Could you please advise?
    thank you

    ReplyDelete