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
// See chapter 3 of this tutorial
// 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;
}
# 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,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
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.
Thanks dude for a nice article.
ReplyDelete4th byte is used for representing luminence value. Is that right?
Thanks Anonymous.
ReplyDeleteThere 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.
Is it because the length of VR type values is always even? Its padded by null 0x0 or space 0x20 if its not.
DeleteCan you please post a link to Dicom Standard document you are referring to
ReplyDelete(example: A.1.2.3 of chapter 3 of the standard)
The latest DICOM standard on the DICOM home page is here:
ReplyDeleteftp://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.
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.
ReplyDeleteThis 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.
ReplyDeleteThanks Greg. I don't know what to say.
ReplyDeleteYes, the length of the elemnt must always be even so RGB has a pading space at the end making it 4 bytes long.
ReplyDeleteWhich parameter should be set to determine display range of image ?
ReplyDeleteI believe you refer to WC/WW - the elements that control the display contrast and brightness.
ReplyDeleteWC - 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.
I need some help (more specific) about saving pixel data of unsigned short image.
ReplyDeleteCan I turn to you directly via email or in any other possible way?
Sure. Send email to info@roniza.com
ReplyDeleteFantastic explanation!!
ReplyDeleteKeep it up. You are doing a great service to DICOM professionals!
I am tryig to learn DICOM in 3 days,for a job intervie,wwhat is the best way to go about that.
ReplyDeleteThanks
Good luck! Well, you've defiantly started in the right place :)
DeleteI 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
So did you get the job? :)
DeleteI'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.
ReplyDeletePlease tell me the logic to apply the VOI LUT in the DICOM Image buffer.
ReplyDeleteI 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.
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?
ReplyDeleteHi Sherif,
DeleteWhat'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
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:
ReplyDeletePatient
->Study1
-->Series1
--->Instance1
-->Series2
->Study2
-->Series1
Hi Andrew,
DeleteThat'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
Thank you Roni, that was very helpful! Now I understand why DICOMDIR is so important :)
DeleteIs 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.
Deletehey 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
ReplyDeletethanks
Is it possible to have multiple 7fe0,0010 elements in a DICOM file?
ReplyDeleteHi. Sorry for the late response.
DeleteOnly 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).
hi all,
ReplyDeleteand 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
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.
ReplyDeleteGood, so the next chapters is for you. C-FIND and C-MOVE.
DeleteThe last chapter (3) was excellent. This chapter... not so much. The definitions weren't clear.
ReplyDeleteWhat causes of patient file merging? I noticed one example of merging is that they have the same study time.
ReplyDeletethanks for great explanation!
ReplyDeleteThank you very much, i was bloqued since 2 days on a dicom project !
ReplyDeleteWhen 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?
ReplyDeleteI 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?
ReplyDeleteOk, nevermind. I found it in the RXDCX official exmaples. If anybody were wondering it's just something like:
DeleteDCXELM el = new DCXELM();
el.Init((int)DICOM_TAGS_ENUM.StudyDescription);
el.Value = "Convert MPEG to DICOM";
output.insertElement(el);
You're wlecome :)
Hi,
ReplyDeleteI have a question about UIDs creation.
Can we have two different studies whith the same SeriesInstanceUID ?
Thanks
Hi
DeleteCan? 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
Hey,
DeleteI 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
can we directly connect 2 dicom nodes through a wire cable and transfer data?
ReplyDeleteWorth a try
Deletecan we directly connect 2 dicom nodes through a wire cable and transfer data
ReplyDeletecan we directly connect 2 dicom nodes through a wire cable and transfer data
ReplyDeleteHi All,
ReplyDeleteIs there a full dicomtags reference we can check?
I got 0008,0070 and it seems like the Machine Manufaturer but I am guessing...
Great explanation!
ReplyDeleteI 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.
Hi,
DeleteWhen 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
I see. Thanks!
DeleteDear Experts,
ReplyDeleteI 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!
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/
DeleteOpen the files using DICOMIZER: http://downloads.roniza.com/downloads/dicomizer/5.3.2/
and click CTRL-H to view the tags.
Let me know ...
Hey,
ReplyDeleteI 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!
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
DeleteThanks for making DICOM easy for me.
ReplyDeleteThats really a treasure for me.
Quite an interesting read.
Thanks
Hi,
ReplyDeleteI'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!
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