This example shows how to use the Radiomics package to directly instantiate the feature classes for feature extraction.
Note that this is not the intended standard use. For an example on the standard use with feature extractor, see the helloRadiomics
example.
In [26]:
from __future__ import print_function
import os
import collections
import SimpleITK as sitk
import numpy
import six
import radiomics
from radiomics import firstorder, glcm, imageoperations, shape, glrlm, glszm
Test cases can be downloaded to temporary files. This is handled by the radiomics.getTestCase()
function, which checks if the requested test case is available and if not, downloads it. It returns a tuple with the location of the image and mask of the requested test case, or (None, None) if it fails.
Alternatively, if the data is available somewhere locally, this directory can be passed as a second argument to radiomics.getTestCase()
. If that directory does not exist or does not contain the testcase, functionality reverts to default and tries to download the test data.
If getting the test case fails, PyRadiomics will log an error explaining the cause.
In [27]:
imageName, maskName = radiomics.getTestCase('brain1')
if imageName is None or maskName is None: # Something went wrong, in this case PyRadiomics will also log an error
raise Exception('Error getting testcase!') # Raise exception to prevent cells below from running in case of "run all"
In [28]:
image = sitk.ReadImage(imageName)
mask = sitk.ReadImage(maskName)
In [29]:
settings = {}
settings['binWidth'] = 25
settings['resampledPixelSpacing'] = None
# settings['resampledPixelSpacing'] = [3, 3, 3] # This is an example for defining resampling (voxels with size 3x3x3mm)
settings['interpolator'] = 'sitkBSpline'
settings['verbose'] = True
In [30]:
# Resample if necessary
interpolator = settings.get('interpolator')
resampledPixelSpacing = settings.get('resampledPixelSpacing')
if interpolator is not None and resampledPixelSpacing is not None:
image, mask = imageoperations.resampleImage(image, mask, **settings)
In [31]:
# Crop the image
# bb is the bounding box, upon which the image and mask are cropped
bb, correctedMask = imageoperations.checkMask(image, mask, label=1)
if correctedMask is not None:
mask = correctedMask
croppedImage, croppedMask = imageoperations.cropToTumorMask(image, mask, bb)
In [32]:
firstOrderFeatures = firstorder.RadiomicsFirstOrder(croppedImage, croppedMask, **settings)
# Set the features to be calculated
firstOrderFeatures.enableFeatureByName('Mean', True)
# firstOrderFeatures.enableAllFeatures()
In [33]:
# Print out the docstrings of the enabled features
print('Will calculate the following first order features: ')
for f in firstOrderFeatures.enabledFeatures.keys():
print(f)
print(getattr(firstOrderFeatures, 'get%sFeatureValue' % f).__doc__)
In [34]:
# Calculate the features and print(out result)
print('Calculating first order features...',)
result = firstOrderFeatures.execute()
print('done')
print('Calculated first order features: ')
for (key, val) in six.iteritems(result):
print(' ', key, ':', val)
In [35]:
shapeFeatures = shape.RadiomicsShape(croppedImage, croppedMask, **settings)
# Set the features to be calculated
# shapeFeatures.enableFeatureByName('Volume', True)
shapeFeatures.enableAllFeatures()
In [36]:
# Print out the docstrings of the enabled features
print('Will calculate the following shape features: ')
for f in shapeFeatures.enabledFeatures.keys():
print(f)
print(getattr(shapeFeatures, 'get%sFeatureValue' % f).__doc__)
In [37]:
# Calculate the features and print(out result)
print('Calculating shape features...',)
result = shapeFeatures.execute()
print('done')
print('Calculated shape features: ')
for (key, val) in six.iteritems(result):
print(' ', key, ':', val)
In [38]:
glcmFeatures = glcm.RadiomicsGLCM(croppedImage, croppedMask, **settings)
# Set the features to be calculated
# glcmFeatures.enableFeatureByName('SumEntropy', True)
glcmFeatures.enableAllFeatures()
In [39]:
# Print out the docstrings of the enabled features
print('Will calculate the following GLCM features: ')
for f in glcmFeatures.enabledFeatures.keys():
print(f)
print(getattr(glcmFeatures, 'get%sFeatureValue' % f).__doc__)
In [40]:
# Calculate the features and print(out result)
print('Calculating GLCM features...',)
result = glcmFeatures.execute()
print('done')
print('Calculated GLCM features: ')
for (key, val) in six.iteritems(result):
print(' ', key, ':', val)
In [41]:
glrlmFeatures = glrlm.RadiomicsGLRLM(croppedImage, croppedMask, **settings)
# Set the features to be calculated
# glrlmFeatures.enableFeatureByName('ShortRunEmphasis', True)
glrlmFeatures.enableAllFeatures()
In [42]:
# Print out the docstrings of the enabled features
print('Will calculate the following GLRLM features: ')
for f in glrlmFeatures.enabledFeatures.keys():
print(f)
print(getattr(glrlmFeatures, 'get%sFeatureValue' % f).__doc__)
In [43]:
# Calculate the features and print(out result)
print('Calculating GLRLM features...',)
result = glrlmFeatures.execute()
print('done')
print('Calculated GLRLM features: ')
for (key, val) in six.iteritems(result):
print(' ', key, ':', val)
In [44]:
glszmFeatures = glszm.RadiomicsGLSZM(croppedImage, croppedMask, **settings)
# Set the features to be calculated
# glszmFeatures.enableFeatureByName('LargeAreaEmphasis', True)
glszmFeatures.enableAllFeatures()
In [45]:
# Print out the docstrings of the enabled features
print('Will calculate the following GLSZM features: ')
for f in glszmFeatures.enabledFeatures.keys():
print(f)
print(getattr(glszmFeatures, 'get%sFeatureValue' % f).__doc__)
In [46]:
# Calculate the features and print(out result)
print('Calculating GLSZM features...',)
result = glszmFeatures.execute()
print('done')
print('Calculated GLSZM features: ')
for (key, val) in six.iteritems(result):
print(' ', key, ':', val)
Calculating features on filtered images is very similar to calculating features on the original image. All filters in PyRadiomics have the same input and output signature, and there is even one for applying no filter. This enables to loop over a list of requested filters and apply them in the same piece of code. It is applied like this in the execute function in feature extractor. The input for the filters is the image, with additional keywords. If no additional keywords are supplied, the filter uses default values where applicable. It returns a generator object, allowing to define the generators to be applied before the filters functions are actually called.
In [47]:
logFeatures = {}
sigmaValues = [1.0, 3.0, 5.0]
for logImage, imageTypename, inputSettings in imageoperations.getLoGImage(image, mask, sigma=sigmaValues):
logImage, croppedMask = imageoperations.cropToTumorMask(logImage, mask, bb)
logFirstorderFeatures = firstorder.RadiomicsFirstOrder(logImage, croppedMask, **inputSettings)
logFirstorderFeatures.enableAllFeatures()
logFeatures[imageTypename] = logFirstorderFeatures.execute()
In [48]:
# Show result
for sigma, features in six.iteritems(logFeatures):
for (key, val) in six.iteritems(features):
laplacianFeatureName = '%s_%s' % (str(sigma), key)
print(' ', laplacianFeatureName, ':', val)
In [49]:
waveletFeatures = {}
for decompositionImage, decompositionName, inputSettings in imageoperations.getWaveletImage(image, mask):
decompositionImage, croppedMask = imageoperations.cropToTumorMask(decompositionImage, mask, bb)
waveletFirstOrderFeaturs = firstorder.RadiomicsFirstOrder(decompositionImage, croppedMask, **inputSettings)
waveletFirstOrderFeaturs.enableAllFeatures()
print('Calculate firstorder features with ', decompositionName)
waveletFeatures[decompositionName] = waveletFirstOrderFeaturs.execute()
In [50]:
# Show result
for decompositionName, features in six.iteritems(waveletFeatures):
for (key, val) in six.iteritems(features):
waveletFeatureName = '%s_%s' % (str(decompositionName), key)
print(' ', waveletFeatureName, ':', val)