Tuesday, June 27, 2023

Introduction to DICOM - Chapter 4 - DICOM Objects


Chapter 4 – DICOM Objects
In chapter 3 we’ve learned about DICOM elements. Every element is one piece of typed data with a pre defined, well specified meaning. There are thousands of DICOM elements (See chapter 6 of the standard) from the very basic attributes of patient name and birth date to the most esoteric uses of 3D surface vortices. In this chapter we’re going to collect elements into image object that is called Secondary Capture Image. 

The guys at DICOM did a lot of very good work and created well defined classes for a very detailed Data Model. This is why I always advise to dig in the DICOM standard before designing your imaging device software because there’s a very good chance that the DICOM technical committees already did the work for you and you can save a lot of expansive design time this way. 

In a way DICOM objects definitions are similar to object oriented programming. I prefer though the analog to interfaces specifications. The motivation to adhere to a standard is to enable interoperability. By detailing information object definitions (IOD’s) DICOM enables us to exchange virtual objects between applications without knowing in advance anything about the application we are going to interface with. 

In this chapter I'm going to complete chapter’s 3 examples by adding elements to the object until it’s a valid Secondary Capture Image according to the DICOM standard. Secondary Capture Image is the simplest DICOM image object. Secondary Captures is not related to any specific device. It has the very basic set of elements that a DICOM application needs in order to display and archive a DICOM image properly.

The DICOM Data Model

The specification of DICOM objects are documented in chapter 3 of the DICOM standard that defines the DICOM data model. In its most simplified form the DICOM Data Model looks like this. 

A simplified view of the DICOM Data Model


The data model defines Information Entities (IE’s); Patient, Study, Series and Image. There are more IE’s like Visit, Equipment, Clinical Trial, Procedure and many others and they are all defined in chapter 3 which is the longest chapter of the standard. The DICOM Data Model that is made of IE's is normalized. It is a perfect relational database definition. The classes of the DICOM Objects however are composites made of modules from different entities. The integration is achieved by applications that exchange composite objects between one another. Each application is responsible for it's own internal normalized database that is private to itself and should not interest any other application and is out of the standard's scope. The way you build your DICOM application internals is completely your business. The only thing that matters is your interfaces. Your application should talk proper DICOM. By the way, the DICOM network protocol that we’ll get to in later chapters also makes a distinction between Normalized and Composite operations and there’s N protocol and C protocol with different commands for each one.

The classes of the DICOM static data model are called SOP Classes and are defined by IOD’s – Information Object Definition. IOD’s are specified in Appendix A of chapter 3 of the standard. An IOD is a collection of Modules and a Module is a collection of elements from one information entity that together represent something. The modules are also defined in chapter 3 of the DICOM standard in appendix C. Two object oriented concepts, composition and reuse, that are used by DICOM is the Modules that are parts shared between different IOD’s.

All DICOM Objects must include the SOP Common Module and modules from the four main IE’s: Patient, Study, Series and Image (Image and Instance are the same in DICOM. Once there were only images but then objects that are not images has been defined and the name thus changed from Image to Instance in order to represent an instance of a SOP class). All DICOM Images, that is DICOM Instances that Are Images, must include the Image Module. Because Every DICOM Object must be part of a Series, all DICOM Objects must include the General Series Module and because all series must be part of a Study, every DICOM Object must include the General Study Module and because every study is made on some patient, all DICOM objects must have a Patient Module. You probably wonder what SOP means? That's an acronym for "Service Object Pair" and please take my word for it, that for now this is all we need to say about that. Maybe when we talk about DICOM Services or understanding DICOM Conformance Statements I'll try to explain where this name comes from, but I'm not sure that it makes much difference. In a word, SOP is a pair of a DICOM Sevice and and DICOM Object like Secondary Capture Object and Storage Service.

Secondary Capture Image IOD

With that understanding at hand, let’s look at the SC Image IOD Modules from section A.8.1.3 of the standard. It looks like this:

IE
Module
Reference
Usage
Patient
Patient
C.7.1.1
M

Clinical Trial Subject
C.7.1.3
U
Study
General Study
C.7.2.1
M

Patient Study
C.7.2.2
U

Clinical Trial Study
C.7.2.3
U
Series
General Series
C.7.3.1
M

Clinical Trial Series
C.7.3.2
U
Equipment
General Equipment
C.7.5.1
U

SC Equipment
C.8.6.1
M
Image
General Image
C.7.6.1
M

Image Pixel
C.7.6.3
M

Device
C.7.6.12
U

Specimen
C.7.6.22
U

SC Image
C.8.6.2
M

Overlay Plane
C.9.2
U

Modality LUT
C.11.1
U

VOI LUT
C.11.2
U

SOP Common
C.12.1
M

Taking out all the lines marked with a U that mark these modules as User optional and leaving only the M lines that stand for Mandatory modules and we are left with eight modules that one of them is actually empty as you will soon find out.

IE
Module
Reference
Usage
Patient
Patient
C.7.1.1
M
Study
General Study
C.7.2.1
M
Series
General Series
C.7.3.1
M
Equipment
SC Equipment
C.8.6.1
M
Image
General Image
C.7.6.1
M

Image Pixel
C.7.6.3
M

SC Image
C.8.6.2
M

SOP Common
C.12.1
M

Note also that in this table there are only two modules that are specific to SC and all the other modules are general and common modules that are shared by many IOD’s. It's very common in DICOM that the mandatory elements are very few and there are a lot of optional elements. This is not unique to the DICOM standard and is common to many standards and sometime leads to uncertainties and ambiguities or gaps as we sometime call them. These gaps led IHE to publish technical frameworks that further specify the use of the standard and narrow the options. The IHE initiative is a great success and participating in IHE connect-a-thon is an outstanding opportunity to test systems in a very realistic integration environment. 

During the design of your application, when you need to add some data to an object and don’t find a proper place for it, remember these optional modules that we’ve omitted here and look for a place to put your data in them before defining private elements, modules and objects. DICOM let you define new elements that are called private elements and we’ll look at that later on but as already said more than once, there’s a very good chance that these guys have already did the work for you and defined a solution to your problem and went through the process of validating it and it is probably documented very well in the standard. After all, the DICOM standard is more than 3,000 pages long.

Element Types

To finish our digging in the DICOM standard, we now need to replace every line in the modules table with the module's definition from appendix C of chapter 3 of the DICOM standard. If you look at the standard you will see that every module is rather large and includes many elements but luckily, like the optional modules, many of the elements are optional too. In the modules tables elements are marked with a ‘Type’ column that can be 1 for Mandatory with actual value (not zero length), 2 for Mandatory that can be null (zero length) or 3 for optional. 1 and 2 can also have a ‘C’ for conditional so 1C is mandatory if some condition, that is detailed in the module table, is met and the same for 2C. 

So we are now going to copy the modules but only the 1 and 2 elements dumping all the 3’s and also 1C and 2C’s that their condition is obviously not met for our example. Remember that we are talking interoperability so striving to the simplest object that as many systems as possible can understand is our goal. 

Next to every element I’m going to add the C# code to add it into the object and at the end we’re going to have all the code at hand.

Unique Identifiers (UID’s)

One last thing, before we dive into the code, I’d like to say a word about Unique Identifiers. DICOM makes extensive use of Unique Identifiers. Almost every entity in the DICOM Data Model has a unique identifier. In DICOM every SOP Class have its UID. All pre-define UID’s including the SOP Class UID’s are documented in chapter 6 of the DICOM standard. A DICOM Object is an Instance of such class and is called SOP Instance and it also has a UID called SOP Instance UID. DICOM defines a mechanism in order to make sure UID’s are globally Unique. Every DICOM application should acquire a ‘root’ UID that is used as a prefix to the UID’s it creates. Every entity in the DICOM Data Model also has a UID with the exception of the patient. Patients are identified using the combination of their name and ID. Studies, Series, all have UID’s. DICOM Archives (PACS) should use the UID’s to index their databases so when other applications make searches (Queries) they can refer to objects using the UID’s and the archive can respond to the searches quickly. 

As I said earlier, every DICOM Image Object has patient, study, series, and image modules. In our example we’ll generate new UID’s for Series Instance UID and SOP Instance UID (that is the Image UID). In "proper" DICOM integration the Study Instance UID is provided by the department IT system (RIS/PACS) through a DICOM service called Modality Worklist but devices can default to creating the Study Instance UID if it’s not provided from an external system. The Series Instance UID and SOP Instance UID are always generated by the Imaging device. The definition of a DICOM series is a set of DICOM Instances that were generated together by the same equipment at the same operation. You can read the exact definition in section A.1.2.3 of chapter 3 of the standard.


Creating a Secondary Capture DICOM Image
// create the object
DCXOBJ o = new DCXOBJ();
Table C.7-1
 PATIENT MODULE ATTRIBUTES

Attribute Name
Tag
Type
Attribute Description
// Create element
DCXELM e = new DCXELM();

Patient's Name
(0010,0010)
2
Patient's full name.
// Patient name
// But we set it to "DOE^JOHN"
e.Init((int)DICOM_TAGS_ENUM.PatientsName);
o.insertElement(e);
Patient ID
(0010,0020)
2
Primary hospital identification number or code for the patient.
// Patient ID - type 2 can be empty
e.Init((int)DICOM_TAGS_ENUM.patientID);
o.insertElement(e);
Patient's Birth Date
(0010,0030)
2
Birth date of the patient.
e.Init((int)DICOM_TAGS_ENUM.PatientBirthDate);
o.insertElement(e);
Patient's Sex
(0010,0040)
2
Sex of the named patient.
Enumerated Values:
            M = male
            F = female
            O = other
e.Init((int)DICOM_TAGS_ENUM.PatientsSex);
o.insertElement(e);

Table C.7-3
GENERAL STUDY MODULE ATTRIBUTES

Attribute Name
Tag
Type
Attribute Description

Study Instance UID
(0020,000D)
1
Unique identifier for the Study.
// Let's assume we got a Study Instance
// UID from the department IT system
// and that it's 1.2.3.4.5.6.7
e.Init((int)DICOM_TAGS_ENUM.studyInstanceUID);
e.Value = "1.2.3.4.5.6.7";
o.insertElement(e);
Study Date
(0008,0020)
2
Date the Study started.
// Let's say the study was created now         e.Init((int)DICOM_TAGS_ENUM.StudyDate);
e.Value = DateTime.Now;
o.insertElement(e);
Study Time
(0008,0030)
2
Time the Study started.
e.Init((int)DICOM_TAGS_ENUM.StudyTime);
e.Value = DateTime.Now;
o.insertElement(e);
Referring Physician's Name
(0008,0090)
2
Name of the patient's referring physician
e.Init((int)DICOM_TAGS_ENUM.ReferringPhysicianName);
o.insertElement(e);

Study ID
(0020,0010)
2
User or equipment generated Study identifier.
e.Init((int)DICOM_TAGS_ENUM.StudyID);
o.insertElement(e);
Accession Number
(0008,0050)
2
A RIS generated number that identifies the order for the Study.
e.Init((int)DICOM_TAGS_ENUM.AccessionNumber);
o.insertElement(e);
Table C.7-5a
GENERAL SERIES MODULE ATTRIBUTES

Attribute Name
Tag
Type
Attribute Description

Modality
(0008,0060)
1
Type of equipment that originally acquired the data used to create the images in this Series. See C.7.3.1.1.1 for Defined Terms.
// Modality is type 1 in 
// Generalseries module but
// it is also type 3 in SC
// Equipment module that
// overtakes in this case so we
// can leave it out of the object
Series Instance UID
(0020,000E)
1
Unique identifier of the Series.
// Let's generate a
// Series Instance UID
DCXUID uid = new DCXUID();
e.Init((int)DICOM_TAGS_ENUM.seriesInstanceUID);
e.Value = uid.CreateUID(UID_TYPE.UID_TYPE_SERIES);
o.insertElement(e);
Series Number
(0020,0011)
2
A number that identifies this Series.
e.Init((int)DICOM_TAGS_ENUM.SeriesNumber);
o.insertElement(e);
Laterality
(0020,0060)
2C
Laterality of (paired) body part examined. Required if the body part examined is a paired structure and Image Laterality (0020,0062) or Frame Laterality (0020,9072) are not sent. Enumerated Values:
            R = right
            L = left
Note:        Some IODs support Image Laterality (0020,0062) at the Image level or Frame Laterality(0020,9072) at the Frame level in the Frame Anatomy functional group macro, which can provide a more comprehensive mechanism for specifying the laterality of the body part(s) being examined.
e.Init((int)DICOM_TAGS_ENUM.Laterality);
o.insertElement(e);
Table C.8-24
SC EQUIPMENT MODULE ATTRIBUTES

Attribute Name
Tag
Type
Attribute Description

Conversion Type
(0008,0064)
1
Describes the kind of image conversion. Defined Terms :
            DV       = Digitized Video
            DI         = Digital Interface
            DF        = Digitized Film
            WSD    = Workstation
            SD       = Scanned Document
            SI         = Scanned Image
            DRW    = Drawing
            SYN     = Synthetic Image
e.Init((int)DICOM_TAGS_ENUM.ConversionType);
e.Value = "DRW";
o.insertElement(e);
Modality
(0008,0060)
3
Source equipment for the image. This type definition shall override the definition in the General Series Module.
See C.7.3.1.1.1 for Defined Terms.
// See comment above about Modality
Note that here I left in a type 3 element named Modality. Read the description and see why. What it says here is that a SC image doesn’t have to have a Modality tag.

Table C.7-9
GENERAL IMAGE MODULE ATTRIBUTES

Attribute Name
Tag
Type
Attribute Description

Instance Number
(0020,0013)
2
A number that identifies this image.
Note:        This Attribute was named Image Number in earlier versions of this Standard.
e.Init((int)DICOM_TAGS_ENUM.InstanceNumber);
o.insertElement(e);
Patient Orientation
(0020,0020)
2C
Patient direction of the rows and columns of the image. Required if image does not require Image Orientation (Patient) (0020,0037) and Image Position (Patient) (0020,0032). May be present otherwise. See C.7.6.1.1.1 for further explanation.
Note:        IOD’s may have attributes other than Patient Orientation, Image Orientation, or Image Position (Patient) to describe orientation in which case this attribute will be zero length.
// Let's assume the condition
// for all the 2C's bellow
// is not met
Content Date
(0008,0023)
2C
The date the image pixel data creation started. Required if image is part of a series in which the images are temporally related.
Note:        This Attribute was formerly known as Image Date.

Content Time
(0008,0033)
2C
The time the image pixel data creation started. Required if image is part of a series in which the images are temporally related.

Table C.7-11b
IMAGE PIXEL MACRO ATTRIBUTES
// The Image Pixel module is
// completely set by RZDCX when
// we insert the bitmap or jpeg
// We'll discuss this module later on
o.SetBMPFrames("my_image.bmp");
Attribute Name
Tag
Type
Attribute Description

Samples per Pixel
(0028,0002)
1
Number of samples (planes) in this image. See C.7.6.3.1.1 for further explanation.

Photometric Interpretation
(0028,0004)
1
Specifies the intended interpretation of the pixel data. See C.7.6.3.1.2 for further explanation.

Rows
(0028,0010)
1
Number of rows in the image.

Columns
(0028,0011)
1
Number of columns in the image

Bits Allocated
(0028,0100)
1
Number of bits allocated for each pixel sample. Each sample shall have the same number of bits allocated. See PS 3.5 for further explanation.

Bits Stored
(0028,0101)
1
Number of bits stored for each pixel sample. Each sample shall have the same number of bits stored. See PS 3.5 for further explanation.

High Bit
(0028,0102)
1
Most significant bit for pixel sample data. Each sample shall have the same high bit. See PS 3.5  for further explanation.

Pixel Representation
(0028,0103)
1
Data representation of the pixel samples. Each sample shall have the same pixel representation. Enumerated Values:
            0000H = unsigned integer.
            0001H = 2's complement

Pixel Data
(7FE0,0010)
1C
A data stream of the pixel samples that comprise the Image. See C.7.6.3.1.4 for further explanation.
Required if Pixel Data Provider URL (0028,7FE0) is not present.

Planar Configuration
(0028,0006)
1C
Indicates whether the pixel data are sent color-by-plane or color-by-pixel. Required if Samples per Pixel (0028,0002) has a value greater than 1. See C.7.6.3.1.3 for further explanation.

Note: in the Image Pixel Module I left out all the 1C elements related to Palette because we’re going to create here a RGB image.

Table C.8-25
SC IMAGE MODULE ATTRIBUTES

Note: all the elements in this module are type 3.

Table C.12-1
SOP COMMON MODULE ATTRIBUTES

Attribute Name
Tag
Type
Attribute Description

SOP Class UID
(0008,0016)
1
Uniquely identifies the SOP Class. See C.12.1.1.1 for further explanation. See also PS 3.4.
// The SOP Class UID of
// SC Image is
e.Init((int)DICOM_TAGS_ENUM.sopClassUid);
e.Value = "1.2.840.10008.5.1.4.1.1.7";
o.insertElement(e);
SOP Instance UID
(0008,0018)
1
Uniquely identifies the SOP Instance. See C.12.1.1.1 for further explanation. See also PS 3.4.
// We've instanciated a DCXUID
// above. Let's use it again
// to create a SOP Instance UID
e.Init((int)DICOM_TAGS_ENUM.sopInstanceUID);
e.Value = uid.CreateUID(UID_TYPE.UID_TYPE_INSTANCE);
o.insertElement(e);
Specific Character Set
(0008,0005)
1C
Character Set that expands or replaces the Basic  Graphic Set.
Required if an expanded or replacement character set is used.
See C.12.1.1.2 for Defined Terms.
// Let's default to latin 1
// and leave it out



Now it’s time to add a dump command at the end of this code and see what we’ve got. Here’s the complete function:


        public DCXOBJ CreateSCImage()
        {
            // create the object
            DCXOBJ o = new DCXOBJ();
            // Create element
            DCXELM e = new DCXELM();
            // Patient name
            // But we set it to "DOE^JOHN"
            e.Init((int)DICOM_TAGS_ENUM.PatientsName);
            o.insertElement(e);
            // Patient ID - type 2 can be empty
            e.Init((int)DICOM_TAGS_ENUM.patientID);
            o.insertElement(e);

            e.Init((int)DICOM_TAGS_ENUM.PatientBirthDate);
            o.insertElement(e);

            e.Init((int)DICOM_TAGS_ENUM.PatientsSex);
            o.insertElement(e);

            // Let's assume we got a Study Instance
            // UID from the department IT system
            // and that it's 1.2.3.4.5.6.7
            e.Init((int)DICOM_TAGS_ENUM.studyInstanceUID);
            e.Value = "1.2.3.4.5.6.7";
            o.insertElement(e);

            e.Init((int)DICOM_TAGS_ENUM.PatientsSex);
            o.insertElement(e);

            // Let's say the study was created now
            e.Init((int)DICOM_TAGS_ENUM.StudyDate);
            e.Value = DateTime.Now;
            o.insertElement(e);

            e.Init((int)DICOM_TAGS_ENUM.StudyTime);
            e.Value = DateTime.Now;
            o.insertElement(e);

            e.Init((int)DICOM_TAGS_ENUM.ReferringPhysicianName);
            o.insertElement(e);

            e.Init((int)DICOM_TAGS_ENUM.StudyID);
            o.insertElement(e);

            e.Init((int)DICOM_TAGS_ENUM.AccessionNumber);
            o.insertElement(e);

            // Modality is type 1 in 
            // Generalseries module but
            // it is also type 3 in SC
            // Equipment module that
            // overtakes in this case so we
            // can leave it out of the object

            // Let's generate a
            // Series Instance UID
            DCXUID uid = new DCXUID();
            e.Init((int)DICOM_TAGS_ENUM.seriesInstanceUID);
            e.Value = uid.CreateUID(UID_TYPE.UID_TYPE_SERIES);
            o.insertElement(e);

            e.Init((int)DICOM_TAGS_ENUM.SeriesNumber);
            o.insertElement(e);

            e.Init((int)DICOM_TAGS_ENUM.Laterality);
            o.insertElement(e);


            e.Init((int)DICOM_TAGS_ENUM.ConversionType);
            e.Value = "DRW";
            o.insertElement(e);

            // See comment above about Modality

            e.Init((int)DICOM_TAGS_ENUM.InstanceNumber);
            o.insertElement(e);

            // Let's assume the condition
            // for all the 2C's bellow
            // is not met

            // The Image Pixel module is
            // completely set when
            // we insert set the bitmap or jpeg
            // See chapter 3 of this tutorial.
            // We'll discuss this module later on
            o.SetBMPFrames("my_image.bmp");

            // The SOP Class UID of
            // SC Image is
            e.Init((int)DICOM_TAGS_ENUM.sopClassUid);
            e.Value = "1.2.840.10008.5.1.4.1.1.7";
            o.insertElement(e);

            // We've instanciated a DCXUID
            // above. Let's use it again
            // to create a SOP Instance UID
            e.Init((int)DICOM_TAGS_ENUM.sopInstanceUID);
            e.Value = uid.CreateUID(UID_TYPE.UID_TYPE_INSTANCE);
            o.insertElement(e);

            // Let's default to latin 1
            // and leave the character set out

            // Let's dump the object to text file
            o.Dump("my_image.txt");


            // And don't forget to save it too
            o.saveFile("my_image.dcm");

            return o;
        }

And here’s the dump:

# Dicom-Data-Set
# Used TransferSyntax: UnknownTransferSyntax
(0008,0016) UI =SecondaryCaptureImageStorage            #  26, 1 SOPClassUID
(0008,0018) UI [2.16.124.113543.6021.1.3.3727584845.2784.1322776593.2] #  54, 1 SOPInstanceUID
(0008,0020) DA [20111201]                               #   8, 1 StudyDate
(0008,0030) TM [235633.000]                             #  10, 1 StudyTime
(0008,0050) SH (no value available)                     #   0, 0 AccessionNumber
(0008,0064) CS [DRW]                                    #   4, 1 ConversionType
(0008,0090) PN (no value available)                     #   0, 0 ReferringPhysicianName
(0010,0010) PN (no value available)                     #   0, 0 PatientName
(0010,0020) LO (no value available)                     #   0, 0 PatientID
(0010,0030) DA (no value available)                     #   0, 0 PatientBirthDate
(0010,0040) CS (no value available)                     #   0, 0 PatientSex
(0020,000d) UI [1.2.3.4.5.6.7]                          #  14, 1 StudyInstanceUID
(0020,000e) UI [2.16.124.113543.6021.1.2.3727584845.2784.1322776593.1] #  54, 1 SeriesInstanceUID
(0020,0010) SH (no value available)                     #   0, 0 StudyID
(0020,0011) IS (no value available)                     #   0, 0 SeriesNumber
(0020,0013) IS (no value available)                     #   0, 0 InstanceNumber
(0020,0060) CS (no value available)                     #   0, 0 Laterality
(0028,0002) US 3                                        #   2, 1 SamplesPerPixel
(0028,0004) CS [RGB]                                    #   4, 1 PhotometricInterpretation
(0028,0006) US 0                                        #   2, 1 PlanarConfiguration
(0028,0010) US 50                                       #   2, 1 Rows
(0028,0011) US 50                                       #   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
(7fe0,0010) OB ff\ff\ff\ff\ff\ff\ff\ff\ff\ff\ff\ff\ff\ff\ff\ff\ff\ff\ff\ff\ff\ff... # 7500, 1 PixelData

Couple of notes about this dump (highlighted).

First you can see the UID of this instance. Whenever you run this code again, a new UID will be generated. The same goes for Series Instance UID.

See the (7fe0,0010) element? This is the pixel data. The pixels from the bitmap image we’ve converted. It is 7500 bytes long because the image I converted is 50x50 and there's 3 bytes per pixel (Red, Green and Blue).

Look at Study Date (0008,0020) and Study Time (0008,0030). The DA (Date) VR (Value Representation) is defined as formatted date string YYYYMMDD and the TM (Time) VR is a time formatted string with format HHMMSS.TTT. You can see that I ran this example four minutes before midnight on December 1st 2011.

Here’s a short quiz: 

Look at the length Photometric Interpretation (0028,0004). The value is “RGB” but the value length is 4 bytes. Why?

This was quite long and complicated chapter covring the DICOM Data Model, Information Entities, Modules, Information Objects Definitions (IOD's), SOP Classes and SOP Instances, Unqiue Identifiers and element types. Most important, we've walked through the process of reading chapter 3 of the standard and translating it to a software that creates the DICOM Object according to the standard specifications. I hope it wasn't too complicated. As always, comments and questions are most welcome.

56 comments:

  1. Thanks dude for a nice article.
    4th byte is used for representing luminence value. Is that right?

    ReplyDelete
  2. Thanks Anonymous.
    There are images with 4 channels: Red, Green Blue and Alpha where the Alpha Channel is the transparency. In this case the value of element (0028,0004) Photometric Interpretation would be "RGBA".
    My question was about the length of (0028,0004) Photometric Interpretation itself. In the example it is "RGB", a 3 characters code string but the length in the DICOM element is 4 and not 3. Hint: this was discussed in chapter 3 when describing the DICOM elements.

    ReplyDelete
    Replies
    1. Is it because the length of VR type values is always even? Its padded by null 0x0 or space 0x20 if its not.

      Delete
  3. Can you please post a link to Dicom Standard document you are referring to
    (example: A.1.2.3 of chapter 3 of the standard)

    ReplyDelete
  4. The latest DICOM standard on the DICOM home page is here:
    ftp://medical.nema.org/medical/dicom/2011/

    Chapter 3 is:
    ftp://medical.nema.org/medical/dicom/2011/11_03pu.pdf

    The file names start with the year (11) and then the chapter number so chapter 3 is 11_03.
    You can download the PDF and Word versions.

    ReplyDelete
  5. The length of all DICOM elements must be even so although RGB is 3 bytes it is padded to 4 to satisfy the rule that you hinted at.

    ReplyDelete
  6. This is one of the best approaches to demonstrating to people how to populate an SOP instance with data using your toolkit. As I said before, your toolkit was well thought out and makes the development straight forward for those of us who are learning DICOM for the first time. Well done.

    ReplyDelete
  7. Thanks Greg. I don't know what to say.

    ReplyDelete
  8. Yes, the length of the elemnt must always be even so RGB has a pading space at the end making it 4 bytes long.

    ReplyDelete
  9. Which parameter should be set to determine display range of image ?

    ReplyDelete
  10. I believe you refer to WC/WW - the elements that control the display contrast and brightness.
    WC - Window Center is the middle of the display range
    WW - Window Width is the width
    The values that will be displayed are in the range WC-WW/2 to WC+WW/2.
    There are other elements that affects the display. I plan to write a post about image display soon.

    ReplyDelete
  11. I need some help (more specific) about saving pixel data of unsigned short image.
    Can I turn to you directly via email or in any other possible way?

    ReplyDelete
  12. Sure. Send email to info@roniza.com

    ReplyDelete
  13. Fantastic explanation!!

    Keep it up. You are doing a great service to DICOM professionals!

    ReplyDelete
  14. I am tryig to learn DICOM in 3 days,for a job intervie,wwhat is the best way to go about that.
    Thanks

    ReplyDelete
    Replies
    1. Good luck! Well, you've defiantly started in the right place :)
      I would suggest the following:
      1. Read this tutorial
      2. Make a list of DICOM toolkits, choose the most relevant for the job (C#/Java Windows/Mac/Linux) and read more about it. If you can play with it to make a Storage SCU and maybe a A Q/R SCU you're doing good
      3. Make sure you know all the buzzwords. Memorize these lists:
      - A list of large players in the industry (GE, Siemens, Fuji, CareStream, McKeson, ...
      - A list of DICOM viewers (ClearCanvas, k-PACS, DicomWorks, ...
      - A list of DICOM Toolkits (RZDCX - figure out the rest ;)
      - DICOM terminology (tag, transfer syntax, ae title, dicom conformance statement, association)
      - Some other technologies (IHE, HL7, WADO
      At that point I think you'll be ready

      Delete
    2. So did you get the job? :)

      Delete
  15. I'm sort of in the same situation where I have to learn this fast. The guy that does Dicom related issues for the company got frustrated and resigned yesterday. The weeks before quitting he continually complained about DiCom and the servers being slow, about 6 seconds to load a single image in the viewer he designed. Client complaining, now they throw me in the fire, yikes. Hopefully I can learn something here to bring the times down.

    ReplyDelete
  16. Please tell me the logic to apply the VOI LUT in the DICOM Image buffer.
    I have extracted the LUT DATA from the VOI LUT Sequence present in the DICOM Header but on applying the LUT, my image is not getting reconstructed. Please help me in this. I have to show the Dicom image buffer after getting VOI LUT applied on the WPF Control Image Viewer and for that i need to convert the proccesed buffer into Bitmap Image.

    ReplyDelete
  17. I am new to medical imaging, I am interested in applying some visualization techniques on tractography on DT-MRI images. What exactly do I need to dig into in terms of DICOM? do I have to study all the details provided here?

    ReplyDelete
    Replies
    1. Hi Sherif,
      What's provided here is very high level background on different aspects of the DICOM standard and it's use. Maybe you can start by learning what data is available to you in the DICOM Objects you get from the MRI and see what is relevant for your work.
      I'm not aware of tractography objects and modules defined by the standard but I suggest that you run your own check on that by browsing through chapter 3 of the standard and looking for relevant modules of the MR Image SOP Class.
      Roni

      Delete
  18. Hi, I have a question about DICOM files. How entities like patient, study, series and instance reference to each other in the file? I assume that one DICOM file can have only one Patient so this one is solved. But I know studies can have several series and these can have several instances. So when constructing DICOM file I should place several studies/series/instances one after another(and then reference it by ID) or enclose them into sequences like this:

    Patient
    ->Study1
    -->Series1
    --->Instance1
    -->Series2
    ->Study2
    -->Series1

    ReplyDelete
    Replies
    1. Hi Andrew,
      That's a very good question and I'm very happy you asked it.
      In most cases, DICOM File holds one DICOM Instance. The only exception to this is new multi-frame objects that use continuations which are not very common yet.
      Every IOD (Information Object Definition) includes modules of the series, study and patient entities as in the example here.
      So all the files that belongs to the same series will all have the same values in their series module and study module and patient module. The same elements with the same values will repeat in every object and in every file.
      You can group files of the same series by checking their series instance uid and group files of the same study by checking their study instance uid.
      With patient I recommend comparing not only the patient id but all four elements: Patient Name, Patient ID, Sex and Birth Date and alerting the user if not all match.
      Regards,
      Roni

      Delete
    2. Thank you Roni, that was very helpful! Now I understand why DICOMDIR is so important :)

      Delete
    3. Is there a way to check how many DICOM instances there are in a series given only one DICOM instance ? That is, any attribute that says this is instance 1 of 110 for example.

      Delete
  19. hey i'm new in dicom and i want to make web application in asp.net about dicom viewer and i have alot of problem can any one help me

    thanks

    ReplyDelete
  20. Is it possible to have multiple 7fe0,0010 elements in a DICOM file?

    ReplyDelete
    Replies
    1. Hi. Sorry for the late response.
      Only inside sequence. For example thumbnails within a DICOMDIR file.
      Every tag in a DICOM object is unique.
      To put lists of same tags you put them in a sequence (like a DICOM 'list').
      The pixel data cn hold many images, for example in DICOM Ultrasound you can have a multi-frame class so that you can put many images in one DICOM object (DICOM file).

      Delete
  21. hi all,

    and given a study with, say, formed by 120 slices, how to identify which image the physician has marked to be printed (printer or films)?

    many thanks!

    francesco

    ReplyDelete
  22. I want to write a utility to query our PACS System for all studies related to a certain Patient ID then be able to pick a particular study from that list and export it to a directory on my windows PC. I am new to DICOM but not new to scripting.

    ReplyDelete
    Replies
    1. Good, so the next chapters is for you. C-FIND and C-MOVE.

      Delete
  23. The last chapter (3) was excellent. This chapter... not so much. The definitions weren't clear.

    ReplyDelete
  24. What causes of patient file merging? I noticed one example of merging is that they have the same study time.

    ReplyDelete
  25. Thank you very much, i was bloqued since 2 days on a dicom project !

    ReplyDelete
  26. When I download a iamge from a DICOM search list,the web application response is [ Reson:A702H image with the same SOP Instance UID is already stored by this AE. The image was not saved.] Do you have any idea about this case and could you give me some suggestion?

    ReplyDelete
  27. I don't get how to actually SET the value of the element. For example, you've written "we set it to "DOE^JOHN" but a cannot see the actual piece of code that does that. Any help with this?

    ReplyDelete
    Replies
    1. Ok, nevermind. I found it in the RXDCX official exmaples. If anybody were wondering it's just something like:
      DCXELM el = new DCXELM();
      el.Init((int)DICOM_TAGS_ENUM.StudyDescription);
      el.Value = "Convert MPEG to DICOM";
      output.insertElement(el);

      You're wlecome :)

      Delete
  28. Hi,
    I have a question about UIDs creation.
    Can we have two different studies whith the same SeriesInstanceUID ?

    Thanks

    ReplyDelete
    Replies
    1. Hi
      Can? yes. Should? no. DICOM Unique Identifiers - UID's should be globally unique. However, sometimes, this doesn't go the way they should.
      The practice that I take is to use all keys from all levels to uniquely identify a DICOM object.
      So if there's a series for example, the key that I'd take to identify it is: Patient ID+Study Instance UID+Series Instance UID
      Roni

      Delete
    2. Hey,

      I would like to hear your opinion regarding my problem and solution.

      I would prefer to do implement my current solution using the strategy you refereed in your reply, but I am having a little problem with the length and uniqueness.

      So instead of using "all keys from all levels to uniquely identify a DICOM object", like you said, I am using a combination of machine ID and timestamp to do that identification.

      I looked in the rules and the only restriction I found was that none of the UID sections could start with zero and the total length can't be greater than 64.

      Do you think that it could be a good approach? or do you know of any problems it could bring?

      Thanks for the tutorial, so many years passed and still useful for so many people.

      Alex

      Delete
  29. can we directly connect 2 dicom nodes through a wire cable and transfer data?

    ReplyDelete
  30. can we directly connect 2 dicom nodes through a wire cable and transfer data

    ReplyDelete
  31. can we directly connect 2 dicom nodes through a wire cable and transfer data

    ReplyDelete
  32. Hi All,
    Is there a full dicomtags reference we can check?
    I got 0008,0070 and it seems like the Machine Manufaturer but I am guessing...

    ReplyDelete
  33. Great explanation!

    I haven't understood well how UIDs are related to other identifiers like patient ID and accession number, and whitch one is actually used for image grouping and retrieval.

    For example, in my hospital, it happens occasionally that the worklist isn't working for some reason, so we'll manually input the accession number and PID into a modality machine, and the images will get sent to the PACS. But in that case, I imagine I haven't retrieved the correct UID for that study. If for instance, I need to continue this exam on a different equipment, also entering the informations manually, wouldn't the equipment create a different UID for the study entity, making the object thus part of a diffent study? We occasionaly have this cenario in my hospital, and the images still get grouped by the PACS, like if the objects were actually grouped by accession number and not by the UID.

    So what are the instance UIDs actually doing?

    Thanks again.

    ReplyDelete
    Replies
    1. Hi,
      When worklist works, the study instance uid is generated by the pacs and provided to the device. When theres no worklist record, the device generates the uid. By keying manually the accession number you allow the pacs to identify the study and link it back to the scheduled procedure that didnt artive to the device due to the failure you describe. As long as you key the accession number correctly of course.
      Roni

      Delete
  34. Dear Experts,

    I am trying to get the Column and Rows information from a Philips-MRI DICOM image. It works ok for some images but fail for another ones. For example, I got '0' looking at the (0028,0010) and (0028,0011):

    In decimal: 40 0 16 0 85 83 2 0 0 2

    in this case, the Rows is 512. What I am doing wrong?
    Thank you all very much!

    ReplyDelete
    Replies
    1. What version of RZDCX are you using? Please make sure you use latest version 2084 from our downloads: http://downloads.roniza.com/downloads/rzdcx/2.0.8.4/
      Open the files using DICOMIZER: http://downloads.roniza.com/downloads/dicomizer/5.3.2/
      and click CTRL-H to view the tags.
      Let me know ...

      Delete
  35. Hey,

    I Really enjoyed reading this article.

    However, I still have several questions about the UID.
    Is the UID a unique identifier to a specific device, or to a specific model?
    For example, if I have Two (DICOM) machines with the same UID can i assume they have the same manufacturer? and even the same model type?
    or none of the above?

    Thank you very much!

    ReplyDelete
    Replies
    1. Thanks. I assume you refer to implementation class uid. This identifies the implementation ie the software. For example all the devices that use our dicom sdk (rzdcx) has the same implementation so they have the same uid. Read here what the dicom standard has to say about it. (Part 3 section d.3.3.2) http://dicom.nema.org/dicom/2013/output/chtml/part07/sect_D.3.html#sect_D.3.3.2

      Delete
  36. Thanks for making DICOM easy for me.
    Thats really a treasure for me.
    Quite an interesting read.
    Thanks

    ReplyDelete
  37. Hi,

    I'm really impressed by how well you've summarized a lot of the main topics in the DICOM standard. I'm only half-way through your 'tutorial posts', but excited to read the rest! It's going to be a lot easier to dive into those heavy standard docs with your handy guides. Thanks!

    ReplyDelete
  38. Thanks a lot, You saved my time. I am able to understand "Anatomy of DICOM" in a very intuitive way and its all because of you. Thank you , Thank you 🙏 so much Roni. You are amazing !!!!!!!!!!

    ReplyDelete