EvilDICOM

C# DICOM Library Homepage

Welcome to the Evil DICOM C# library homepage. Don’t let the name scare you. Evil DICOM is one of the easiest DICOM libraries in the world to use and implement into your .NET applications. You can forget about the byte order, endianiness, tag order, and all of those little details that can make DICOM seem..well…evil. With Evil DICOM you will be able to access DICOM objects and elements in an intuitive object oriented way. This site has tutorials, API documentation, and even little projects that you can download to get you started.

Grab the Wickedest DICOM library in the worldDistributed on Github

The Structure of Evil DICOM Core

DICOM and especially DICOM programming can seem overwhelming at first and so let’s just get a big picture view of the Evil DICOM library. The cornerstones of the core library are really three classes:

DICOMObject

The outermost object of a DICOM File is considered the DICOM object, which is encapsulated in the DICOMObject class. The DICOM object is really just a container for the elements. The real meat of a DICOM object are the elements it contains. You will probably want to do a few things with DICOM elements. The DICOMObject class provides a few methods and properties that help with finding and manipulating the DICOM elements.

AbstractElement

The AbstractElement class is used as a base class for DICOM elements. Elements are the containers of individual pieces of DICOM data that are stored inside of the DICOM object. The elements vary greatly in the type of data that they hold and the AbstractElement class unify and provide access to the similarities of all elements.

DICOMData

The newest addition to the library is the DICOMData class. It came about because of the flexibility needed for DICOM data. In general DICOM data can have one value, multiple values, or be null. While, an array can potentially capture those needs, I have found it is not as easy to work with as strongly typed properties. The DICOMData class helps meet the needs and flexibility necessary for DICOM data as well as provide a simple interface for accessing and manipulating data.

Basic Reading and Writing

Reading DICOM

C#

1

2

3

4

5

6

7

8

9

10

vardcm=DICOMObject.Open(@"MyDICOMFile.dcm");

//You can also read from bytes (eg. a stream)

vardBytes=File.ReadAllBytes(@"MyDICOMFile.dcm");

vardcm=DICOMObject.Read(dBytes);

//***COOL CODE GOES HERE***

//Writing is equally easy

dcm.SaveAs("MyHackedDICOMFile.dcm");

The dcm variable is now a DICOM object. It is in fact the outermost DICOM object from the file string that was input into the Read() method. The DICOMObject class is the main class of Evil DICOM. Of course the DICOM object is really just a container for all of the DICOM elements that you will want to get and luckily for you, it is easy to do. Now that we did the useless task of reading a file and writing it back unchanged, let’s look at some code we can insert in between.

The tag holds all of the identifying information for the element. The IDICOMElement interface also exposes the element’s data, but it is not strongly typed. Because each element can hold different types of data. You can cast the data to a certain type if you know what it is supposed to be, otherwise I will show you some wicked ways of getting the strongly typed data you want.

Generic Data Casting Elements

If you don’t know the underlying VR type, but you know the type of data that it contains, you can always cast to the more generic AbstactElement where T is the type of data. As you can see below, there is an advantage to knowing the actual VR element type because it provides more intuitive methods of data access (eg. the “FirstName” and “LastName” properties of the PersonName class). You lose those on a generic cast.

Specific Casting Elements

Each VR (value representation) has its own class. If you know the underlying VR, you can cast to a VR class to get some handy strong typed variables.

C#

1

2

3

4

5

6

7

8

9

10

11

//The patient's name IDICOMElement

varpName=dcm.FindFirst(TagHelper.PATIENT_NAME);

//The patient's name strong typed for better data access

varstrongName=dcm.FindFirst(TagHelper.PATIENT_NAME)asPersonName;

varfirstName=strongName.FirstName;

varlastName=strongName.LastName;

//You can manipulate this way also

strongName.FirstName="Fred";

strongName.LastName="Flinstone";

Finding DICOM Elements

The DICOMObject class (dcm variable below) provides two properties that give access to all contained elements. The Elements property gives access to the direct children of the DICOM object and the AllElements property returns all descendant elements including children of elements.

C#

1

2

vardirectChildren=dcm.Elements;

varallDescendants=dcm.AllElements;

Of course you might need to be more specific about the elements you want returned. There are several methods to help you get what you need.

C#

1

2

3

4

5

6

7

8

9

10

11

//Finds the first instance of the Group Length element (0002,0000)

varfirstInstance=dcm.FindFirst("00020000");

//Finds all instances of the Group Length element (0002,0000)

varallInstances=dcm.FindAll("00020000");

//Finds all Code Value (0008,0100) elements that are children of Procedure Code Sequence Elements (0008,1032)

Replacing and Removing Elements

Sometimes, you may just want to remove or replace an element. That is easy as well:

C#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

varrefName=newPersonName

{

FirstName="Fred",

LastName="Flinstone",

Tag=TagHelper.REFERRING_PHYSICIAN_NAME

};

//Whatever the referring physicians real name was, it is now Fred Flinstone

dcm.Replace(refName);

//Even if it doesn't exist yet, add it

dcm.ReplaceOrAdd(refName);

//Remove elements by tag

dcm.Remove("00020000");

dcm.Remove(TagHelper.SEGMENT_NUMBER);

Working with DICOM Data

DICOM data containers need to be very flexible. They must be able to have single values, multiple values, and be null. Evil DICOM accommodates these needs with the DICOMData class. This class wraps a list of data of type T and provides easy access to the single data and multiple data. The following demonstrates how to grab a single (first) value and a multiple value property. It might seem weird to use an underscore at first, but when you are digging deep into DICOM, it helps to keep thinks terse but readable.

//The underscore grabs the the multiplicity data (if there is more than one value)

varxyz=position.Data_;//Data as List<T> (in this case List<double>)

varx=xyz[0];

vary=xyz[1];

varz=xyz[2];

Evil DICOM Helpers

There are a lot of details about DICOM that the libary doesn’t expect you to have memorized. There are several helper classes to help with common problems. I suggest you explore the helper classes in the helper folder of the library. Of all helpers, you will probably use the TagHelper the most.

Using the Tag Helper

Now I don’t expect you to have memorized all DICOM tags. There is a class called the TagHelper that is designed to get to tag Ids quickly. The Tag Helper actually returns a Tag object with some useful properties:

Evil DICOM Tag Class

C#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

//Returns a tag that has other useful properties

varwindowTag=TagHelper.WINDOW_CENTER;

//Group string

vargroup=windowTag.Group;

//Element string

varelem=windowTag.Element;

//Whole Tag ID

varfullID=windowTag.CompleteID;

//Using DICOMObject.Find()

varwindowCenter=dcm.FindFirst(TagHelper.WINDOW_CENTER);

Using the UID Helper

While I can’t go through all the helper classes, I wanted to show you one more. Since UIDs are everywhere in DICOM files, you might want to know how to generate some. A nifty little helper class is just for that:

Easy DICOM Selection

I have been saving one of the best features for last. The DICOMSelector used to be a premium feature of the library and now it is included for free. It is all about convenience. Selecting and manipulating DICOM elements is easy with Evil DICOM, but it is even EASIER when you are using the selector. The selector gives you strongly typed access to all elements allowing you to do complex hierarchical descension by dot notation. You never have to manually cast the element with this module.

Hooking Up The Selection Module

Add the following using statement:

C#

1

usingEvilDICOM.Selection;

Wrap your DICOM object

C#

1

2

vardcm=DICOMFileReader.Read("structureSet.dcm");

varsel=newDICOMSelector(dcm);

Using The Selection Module

The following example shows the simple dot descension into an element of the DICOM object. The Selector is just a wrapper around the object that allows for quick access to the elements.

Rex Cardan is a medical physicist for the University of Alabama at Birmingham. As a code ninja, he slings the sharpest of all languages (C#) with great precision and care. As a clinical physicist, he aids in the treatment of cancer with radiation and explores new techniques and technologies to improve treatments of the future.