Getting DICOM structure contours as array in Python
Asked Answered
A

2

11

So if I have an image (CT, MRI, etc.) or even a dose from radiation therapy I can pull out the dose or image values into an array through:

import dicom

ds = dicom.read_file("dicom_file.dcm")

print ds.pixel_array

This is pretty straightforward, and gives me the ability to manipulate images/doses as I want. However, often you also have a structure file that includes different contoured structures that you can then see in an image viewer or something like that. Again, pretty straightforward.

My problem is that I would also like these individual structures as an array as well. And if I run the same code I just get TypeError: No pixel data found in this dataset.

I'm guessing that structure DICOM files are not "made" the same way as dose/images DICOM files.

So is there a solution to this that I haven't been able to find ? I have also looked at the dicompyler_core package, but from what I could see there wasn't any way to "just" get out the different structures into arrays.

The SOP Class UID of the DICOM file in question is RT Structure Set Storage.

Armored answered 10/10, 2017 at 12:26 Comment(0)
C
12

Here is an interactive session illustrating the data layout using the rtstruct.dcm file included with pydicom:

>>> from pydicom.data import get_testdata_file
>>> import pydicom
>>> test_file = get_testdata_file("rtstruct.dcm")
>>> ds = pydicom.dcmread(test_file, force=True)
>>> ds.dir("contour")
['ROIContourSequence']
>>> ctrs = ds.ROIContourSequence
>>> ctrs[0]
(3006, 002a) ROI Display Color                   IS: ['220', '160', '120']
(3006, 0040)  Contour Sequence   3 item(s) ----
   (3006, 0042) Contour Geometric Type              CS: 'CLOSED_PLANAR'
   (3006, 0046) Number of Contour Points            IS: '5'
   (3006, 0048) Contour Number                      IS: '1'
   (3006, 0050) Contour Data                        DS: ['-200.0', '150.0', '-20
0.0', '-200.0', '-150.0', '-200.0', '200.0', '-150.0', '-200.0', '200.0', '150.0
', '-200.0', '-200.0', '150.0', '-200.0']
   ---------
   (3006, 0042) Contour Geometric Type              CS: 'CLOSED_PLANAR'
   (3006, 0046) Number of Contour Points            IS: '6'
   (3006, 0048) Contour Number                      IS: '2'
   (3006, 0050) Contour Data                        DS: ['200.0', '-0.0', '-190.
0', '200.0', '-150.0', '-190.0', '-200.0', '-150.0', '-190.0', '-200.0', '150.0'
, '-190.0', '200.0', '150.0', '-190.0', '200.0', '-0.0', '-190.0']
   ---------
   (3006, 0042) Contour Geometric Type              CS: 'CLOSED_PLANAR'
   (3006, 0046) Number of Contour Points            IS: '6'
   (3006, 0048) Contour Number                      IS: '3'
   (3006, 0050) Contour Data                        DS: ['200.0', '-0.0', '-180.
0', '200.0', '-150.0', '-180.0', '-200.0', '-150.0', '-180.0', '-200.0', '150.0'
, '-180.0', '200.0', '150.0', '-180.0', '200.0', '-0.0', '-180.0']
   ---------
(3006, 0084) Referenced ROI Number               IS: '1'

The data is stored (in this case, as is usual) as a set of coordinates for each plane. To get the data for one contour, for one plane, you could use

>>> ctrs[0].ContourSequence[0].ContourData
['-200.0', '150.0', '-200.0', '-200.0', '-150.0', '-200.0', '200.0', '-150.0', '
-200.0', '200.0', '150.0', '-200.0', '-200.0', '150.0', '-200.0']

These are triplets of (x, y, z) coordinates one after the other.

You can find out more information about each contour (name, etc) in the StructureSetROISequence sequence, for the index given by Referenced ROI Number.

You could get a complete array for all of these by looping through each dataset in the ContourSequence for that particular contour and appending them together into one array.

Cockatiel answered 12/10, 2017 at 18:47 Comment(1)
Thank you for replying. And yes, this is also pretty much where I am at right now. But, and maybe I'm doing it the wrong way, some contours are not what they are supposed to. It's like these coordinates only do the outline of a contour. So if the contour has hole in it, like when you have a bladder wall (for example), I don't seem to get the width of the wall, but more just the outline of the contour. So in principle, the bladder wall and bladder coordinates are pretty much the same, even though the wall should have an outline as well as an inside line. At least that's what I see when plottingArmored
E
0

One way you can visualize the image and any associated dose is with the DicomRTTool (https://github.com/brianmanderson/Dicom_RT_and_Images_to_Mask)

You can install it with

pip install DicomRTTool

Then, use the code as follows to pull image/dose/structure information

from DicomRTTool.ReaderWriter import DicomReaderWriter, sitk
Dicom_path = r'.some_path_to_dicom'
Dicom_reader = DicomReaderWriter(get_dose_output=True)
Dicom_reader.walk_through_folders(Dicom_path) # This will parse through all DICOM present in the folder and subfolders

Dicom_reader.get_images()
Dicom_reader.get_dose()

image_sitk_handle = Dicom_reader.dicom_handle
image_numpy = sitk.GetArrayFromImage(image_sitk_handle)

dose_handle = Dicom_reader.dose_handle
dose_numpy = sitk.GetArrayFromImage(dose_handle)

Hope this helps

Erato answered 31/10, 2023 at 15:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.