Working with an RTStruct File

1,476 views
Skip to first unread message

Semihcan Doken

unread,
Aug 20, 2018, 10:49:00 AM8/20/18
to pyradiomics
Hi, 

I have a question about getting started with pyradiomics. I read in multiple places that pyradiomics does not work with DICOM files and that the files need to be converted to nrrd.
 
I have a set of DICOM image files as well as an RTStruct dicom file that contains the contours of the tumor I want to extract the features of.

I converted the DICOM image files to nrrd files using 3d Slicer. However, I have not been able to convert the RTStructures dicom file to an nrrd using 3d slicer. Only to a .seg.vtm file but not an nrrd file. I googled around and searched in this forum and was not able to find a way to convert the RTStruct file to an nrrd. I found a thread here that talks about converting a 'seg' file to nrrd but that does not help. ( seg file is something different and not an RTstruct I think)
 
I am currently unable to use pyradiomics, because I am not sure how it works. I am a newby but it seems odd to me that RTStruct files would not be easy to use since that seems to be norm in this radiation oncology department where I work. RTStruct is how they store the delineation of the tumors.

So what are my options here? Can I use pyradiomics to calculate features? Would it be better for me to go down the path of using Matlab's CERR? (I have been trying to avoid that) If I really cannot use pyradiomics, how long would it take me to write functions myself that would calculate the features myself? A few months? A year? (crazy question perhaps but I thought that implementing these functions myself could also help me understand the features and what they mean better especially if I have no other option) 

I am currently able to use pydicom to extract the pixels in the image that correspond to the ROI/tumor region which means I can get a map/filter for the ROI.  One idea I have is to try to convert this 'mask' I have (which is a numpy array) to the 'maskName' file I see here in cell 4 of the pyradiomics example code here?
imageName, maskName = radiomics.getTestCase('brain1')  


Thanks a lot for any help.
Best
Semihcan Doken




Andrey Fedorov

unread,
Aug 20, 2018, 11:03:26 AM8/20/18
to sdo...@gmail.com, pyradiomics
Can you take a look at plastimatch convert command to generate mask
volumes? It is also possible to save segmentations from Slicer as
plain NRRD, but it will take more steps.

http://plastimatch.org/plastimatch.html
> --
> You received this message because you are subscribed to the Google Groups "pyradiomics" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to pyradiomics...@googlegroups.com.
> To post to this group, send email to pyrad...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/pyradiomics/47427d96-685e-4e8a-b194-44fc6f9380f5%40googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

Semihcan Doken

unread,
Aug 23, 2018, 11:57:58 PM8/23/18
to pyradiomics
Thanks a lot for recommending plastimatch. It has helped me convert my RTstruct file to an nrrd file. I am no longer getting an error when I try to run the example pyradiomics code provided here. However, the feature vector I get as a result of the calculation on my image and rtstruct data is completely empty.

featureVector = extractor.execute(imageName, maskName)  #featureVector is an empty OrderedDict() after this statement.

I experienced the same when I wrote my own python script that would take the contours and made a mask from it (1s for pixels within the contours and 0s for pixels without), converted it to an nrrd and then ran the same line of code above. I got an empty OrderedDict after extractor.executed without any errors.

I do not know what is going on here. What could be the reason that pyradiomics would not error out, calculate features, but return an empty OrderedDict? Is it some metadata issue? A mismatch?

Thanks a lot for any help.
Semihcan

Joost van Griethuysen

unread,
Aug 24, 2018, 1:28:14 AM8/24/18
to pyradiomics
Most likely one of the sanity checks performed prior to feature extraction failed.
The reason PyRadiomics does not throw an error is to allow for batch processing to continue. However, PyRadiomics does write to the log to let you know what is going on. What is the output to the console when you run PyRadiomics?
Alternatively, you can also try to rerun the extraction with logging enabled.

Regards,

Joost

Op vrijdag 24 augustus 2018 05:57:58 UTC+2 schreef Semihcan Doken:

Andrey Fedorov

unread,
Aug 24, 2018, 11:06:10 AM8/24/18
to pyradiomics
Joost, why not throw the error, which could then be caught by the batch processor? I agree it is confusing that the function returns without errors, but the feature vector is empty.

Semihcan, the first step is probably to take the specific case where it fails, and visualize the segmentation produced by plastimatch in relation to the image being analyzed. You can do this with 3D Slicer (https://slicer.org).

Semihcan Doken

unread,
Aug 27, 2018, 11:30:39 PM8/27/18
to pyradiomics
@Joost,

When the verbosity is kept default setting of `WARNING`, I get no errors or notifications whatsoever. I just get an empty OrderedDict as a result without any messages.

However, when I set 
radiomics.setVerbosity(logging.DEBUG)

I get the following message,

Calculating features with label: 1
Enabled images types: {'Original': {}}
Enabled features: {'firstorder': []}
Current settings: {'minimumROISize': None, 'normalizeScale': 1, 'preCrop': False, 'interpolator': 'sitkBSpline', 'binWidth': 25, 'verbose': True, 'minimumROIDimensions': 1, 'force2Ddimension': 0, 'label': 1, 'resampledPixelSpacing': None, 'additionalInfo': True, 'normalize': False, 'force2D': False, 'padDistance': 5, 'removeOutliers': None, 'distances': [1], 'resegmentRange': None, 'voxelBased': False}
Loading image and mask
Checking mask with label 1
Calculating bounding box

This message does not seem to be telling me what went wrong and why I am getting an empty orderedDict as a result. Or does it? I hope this answers your question of 'What is the output to the console?".

Do I need to do anything else or look some other place to see what the 'log' is telling me or what is written to the console? Is there any way I can see what is going wrong and preventing pyradiomics from giving me the calculated features?

I am trying to figure out what is going on and currently my theory is that the output.nrrd produced by plastimatch has incorrect dimensions. I have 136 slices of 512x512 pixels. The RTstruct file contains 17 different structures/contours. When I use plastimatch to convert the RTstruct to an nrrd, I get an nrrd that has dimensions 3x512x512x136. The dimensions seem off to me. Why 3 in the beginning? It should be 17 perhaps since I have 17 structures.

@AndrewFedorov: I tried to open the nrrd files with 3dSlicer, and I see the slices but not the RTstructs which again makes me think that the problem is with the RTstruct file produced by plastimatch, though I do not know how to fix it. I posted a question on plastimatch forum, and am hoping that I will find a solution there. Other things I am trying:

a) I am asking the 3d slicer forum for step-by-step instructions on how to conert RTstruct file to an nrrd. (as I find 3d slicer confusing)
b) I will try to manually (without using plastimatch) generate my own nrrd files with pynrrd from the numpy arrays that represent the masks and see if that helps me avoid running into this empty dictionary issue. I already tried this with a slice and a corresponding mask file but had the exact same issue as above even though the dimensions were not weird like above. I will see if generating many slices to make a 3d structure will improve things. 

Thanks a lot for any help.

Joost van Griethuysen

unread,
Aug 28, 2018, 4:01:58 AM8/28/18
to pyradiomics
I have to look into it, but from your message, it seems that the output of plastimatch for you is a 4D nrrd, or a 3D nrrd, but color (not grayscale). I don't know why that is happening now, but I think it is the cause for the faillure of the extraction. I will look up why there is no warning or error message.

Can you load your image and the output of plastimatch in python and paste the output of print?
You can use this code:

import SimpleITK as sitk

im_path = r'path\to\image.nrrd'
ma_path = r'path\to\mask.nrrd'

im = sitk.ReadImage(im_path)
ma = sitk.ReadImage(ma_path)

print('image)
print(im)
print('mask')
print(ma)

Regards,

Joost

Op dinsdag 28 augustus 2018 05:30:39 UTC+2 schreef Semihcan Doken:

Joost van Griethuysen

unread,
Aug 28, 2018, 11:14:56 AM8/28/18
to pyradiomics
@federov, I changed the behaviour of PyRadiomics to raising ValueErrors. See PR #420.

Op dinsdag 28 augustus 2018 10:01:58 UTC+2 schreef Joost van Griethuysen:

Semihcan Doken

unread,
Sep 15, 2018, 12:12:58 AM9/15/18
to pyradiomics
Hi,

I am still experiencing difficulties here with the dimensions of the outputs plastimatch convert. I am getting 512x512x136 for the image nrrd and 512x512x135 for the mask nrrd. These are both 3D but the 3rd dimensions do not match. This causes pyradiomics to fail "Image/Mask datatype or size mismatch...." The dimensions of the mask is always 1 less than is necessary in the 3rd dimension even when I try other image series with different number of images.

Here is the output when I print as you requested above:


image
Image (0x7f8e0aade2b0)
  RTTI typeinfo:   itk::Image<float, 3u>
  Reference Count: 1
  Modified Time: 2584
  Debug: Off
  Object Name: 
  Observers: 
    none
  Source: (none)
  Source output name: (none)
  Release Data: Off
  Data Released: False
  Global Release Data: Off
  PipelineMTime: 2559
  UpdateMTime: 2583
  RealTimeStamp: 0 seconds 
  LargestPossibleRegion: 
    Dimension: 3
    Index: [0, 0, 0]
    Size: [512, 512, 136]
  BufferedRegion: 
    Dimension: 3
    Index: [0, 0, 0]
    Size: [512, 512, 136]
  RequestedRegion: 
    Dimension: 3
    Index: [0, 0, 0]
    Size: [512, 512, 136]
  Spacing: [1.17188, 1.17188, 3]
  Origin: [-300, -271, -934.5]
  Direction: 
1 0 0
0 1 0
0 0 1

  IndexToPointMatrix: 
1.17188 0 0
0 1.17188 0
0 0 3

  PointToIndexMatrix: 
0.853333 0 0
0 0.853333 0
0 0 0.333333

  Inverse Direction: 
1 0 0
0 1 0
0 0 1

  PixelContainer: 
    ImportImageContainer (0x7f8e0aade540)
      RTTI typeinfo:   itk::ImportImageContainer<unsigned long, float>
      Reference Count: 1
      Modified Time: 2580
      Debug: Off
      Object Name: 
      Observers: 
        none
      Pointer: 0x134f97000
      Container manages memory: true
      Size: 35651584
      Capacity: 35651584

mask
Image (0x7f8e0d613240)
  RTTI typeinfo:   itk::Image<unsigned char, 3u>
  Reference Count: 1
  Modified Time: 2782
  Debug: Off
  Object Name: 
  Observers: 
    none
  Source: (none)
  Source output name: (none)
  Release Data: Off
  Data Released: False
  Global Release Data: Off
  PipelineMTime: 2757
  UpdateMTime: 2781
  RealTimeStamp: 0 seconds 
  LargestPossibleRegion: 
    Dimension: 3
    Index: [0, 0, 0]
    Size: [512, 512, 135]
  BufferedRegion: 
    Dimension: 3
    Index: [0, 0, 0]
    Size: [512, 512, 135]
  RequestedRegion: 
    Dimension: 3
    Index: [0, 0, 0]
    Size: [512, 512, 135]
  Spacing: [1.08717, 1.08717, 3]
  Origin: [-272.902, -149.47, -934.5]
  Direction: 
1 0 0
0 1 0
0 0 1

  IndexToPointMatrix: 
1.08717 0 0
0 1.08717 0
0 0 3

  PointToIndexMatrix: 
0.919816 0 0
0 0.919816 0
0 0 0.333333

  Inverse Direction: 
1 0 0
0 1 0
0 0 1

  PixelContainer: 
    ImportImageContainer (0x7f8e0d6098f0)
      RTTI typeinfo:   itk::ImportImageContainer<unsigned long, unsigned char>
      Reference Count: 1
      Modified Time: 2778
      Debug: Off
      Object Name: 
      Observers: 
        none
      Pointer: 0x14df99000
      Container manages memory: true
      Size: 35389440
      Capacity: 35389440

Joost van Griethuysen

unread,
Sep 20, 2018, 5:24:58 AM9/20/18
to pyradiomics
You can allow PyRadiomics to resample the mask to the image geometric space by enabling `correctMask`.

Regards,

Joost

Op zaterdag 15 september 2018 06:12:58 UTC+2 schreef Semihcan Doken:
Reply all
Reply to author
Forward
0 new messages