How to Match Contours (ROI) to DICOM files

3,060 views
Skip to first unread message

Semihcan Doken

unread,
Apr 13, 2018, 12:17:34 AM4/13/18
to pydicom
Hi All,

I have a set of dicom images. I can open these images using pydicom 

image_slice_one = pydicom.read_file('CT_1.dcm')   # slice 1
image_slice_two
=
pydicom.read_file('CT_2.dcm')   # slice 2
image_slice_three = pydicom.read_file('CT_3.dcm') # etc

This works and I can even visualize them using matplotlib. So far, so good!

Now, I have a separate .dcm file which contains contours around Regions of Interest. (ROI) I can also open that file,

rt_struct = pydicom.dcmread('RTStructure.dcm') #dicom file that contains the contours

and I see that it contains the locations of the contours, for example

rt_struct.ROIContourSequence[1].ContourSequence[0]
rt_struct
.ROIContourSequence[1].ContourSequence[1]
rt_struct
.ROIContourSequence[2].ContourSequence[55] #etc

Great!

But how I do know which image (dicom file / slice mentioned above) each one of these ContourSequences refers to?

When I use dicompyler (a dicom viewer), I can see the contours overlayed on the images, so clearly the viewer is able to figure out which contoursequence is associated with which image. When I scroll up/down to different slices, the viewer updates the contours (in green in the image below) accordingly.


I want to do the same thing in python. How do I know which belongs to which image? Is there a way of easily doing this? Maybe there is a function that does this. Or there must be some metadata hidden somewhere that is allowing the dicom viewer program to know which contour belongs to which image?

My ultimate goal: to select the pixels in these images that fall within the contours and find their average brightness.

I am new to dicom and pydicom and will greatlly appreciate any insights. My guess is that this is a common need so there is an easy way to do it. 

Thank you very much in advance!
Semihcan


Eli Stevens (Gmail)

unread,
Apr 13, 2018, 2:15:06 AM4/13/18
to pyd...@googlegroups.com
Sadly, it's not going to be easy.  :(

There are two ways I know of to map a given contour to a given CT slice. The first is that each contour should have a referenced CT slice SOP Instance UID somewhere in the tags. Then there's also the Z-value of the contour, which should line up with the Z value of the Patient Position (Image) tag of one of the CT slices. In general, that should Just Work(tm), but out in the real world there are going to be a million wonky things that will prevent it from working out of the box, depending on what data you're using. Hopefully your data is clean enough.

The other tricky part is that you're going to need to map from CT coordinates to patient coordinates, since the contours are in a mm-based coordinate system relative to an arbitrary point inside the patient's body (though the axes usually line up nicely with +x out the left, +y out the back, and +z out the head). Once you've done that, you'll need to do some contour filling to figure out which voxels are inside. Note that the DICOM spec says that a voxel exactly on the border of a contour is always inside the contour, which is unusual for most contour-filling algorithms, so if you need to be exact to the DICOM definition of the ROI, you'll want to pick a library that lets you fill that way.

All of the code that does this that I've written is commercial, so I'm unable to share. :(

Good luck!
Eli


--
You received this message because you are subscribed to the Google Groups "pydicom" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pydicom+unsubscribe@googlegroups.com.
To post to this group, send email to pyd...@googlegroups.com.
Visit this group at https://groups.google.com/group/pydicom.
For more options, visit https://groups.google.com/d/optout.

Aditya Panchal

unread,
Apr 13, 2018, 4:01:31 PM4/13/18
to pyd...@googlegroups.com
Hi Semihcan,

dicompyler is written in Python using pydicom so you can definitely follow the source code [1] to figure out how to render contours on CT slices. As Eli mentioned, one of the easiest ways is to find the z-coordinate of the contour sequence and render the contour data when it matches the z-coordinate of the CT data.

If you use the dicompyler-core library, there is a function `GetStructureCoordinates` in dicomparser [2] that returns the coordinates as a dictionary sorted by z-position.

However, your ultimate goal almost sounds like getting a CT histogram bounded by contour data. The best way to do that would be to convert the data to voxel space then mask the voxellized structure data over the CT data to get the voxels bounded by structure. You could do this CT slice by slice. A good reference is the DVH calculation algorithm used by dicompyler [3] (although in your case you could replace the concept of dose by CT image).

If you have questions specific to dicompyler, there is also a google group for the project located here: https://groups.google.com/forum/#!forum/dicompyler

Hope that helps,

Adit

p.dwyer3....@gmail.com

unread,
Jul 5, 2018, 9:19:54 AM7/5/18
to pydicom
Hi Adit,

Firstly, dicompyler is great a great, great program. Quick question for you. If I wanted to recalculate the DVH using the EQD2, where would I do this or is it possible? As in, where does the calculated DVH output to or where is it calculated before it i graphed? 

I am quite new to python so am trying to figure it out.

Any help is very much appreciated.
Paddy
To unsubscribe from this group and stop receiving emails from it, send an email to pydicom+u...@googlegroups.com.

To post to this group, send email to pyd...@googlegroups.com.
Visit this group at https://groups.google.com/group/pydicom.
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "pydicom" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pydicom+u...@googlegroups.com.

Aditya Panchal

unread,
Jul 5, 2018, 10:33:52 PM7/5/18
to pyd...@googlegroups.com
Hi Paddy,

Thanks for the kind words. I'm not sure if you are working with Rhonda but these messages came in at the same time. I'll refer you to the answer I gave on the dicompyler group to keep it on topic: https://groups.google.com/d/topic/dicompyler/DVmIBc8tiQ4/discussion

Best,

Aditya

To unsubscribe from this group and stop receiving emails from it, send an email to pydicom+unsubscribe@googlegroups.com.

Paddy Dwyer

unread,
Jul 6, 2018, 6:22:11 AM7/6/18
to pyd...@googlegroups.com
Thanks Aditya,

Yes I know Rhonda (she is my girlfriend) and I am trying to help her out cause I have a coding background but not in Python unfortunately. Plus she is at the opposite side of the country so we are trying to solve her code via distance. 

I will have a look at the topic and post any questions I have to that.

Again, well done on the program, it's really good. 

Paddy  
Reply all
Reply to author
Forward
0 new messages