コード例 #1
0
    def loadImage(self, ImageFilePath, MaskFilePath):
        """
    Preprocess the image and labelmap.
    If ImageFilePath is a string, it is loaded as SimpleITK Image and assigned to image,
    if it already is a SimpleITK Image, it is just assigned to image.
    All other cases are ignored (nothing calculated).
    Equal approach is used for assignment of mask using MaskFilePath.

    If normalizing is enabled image is first normalized before any resampling is applied.

    If resampling is enabled, both image and mask are resampled and cropped to the tumor mask (with additional
    padding as specified in padDistance) after assignment of image and mask.
    """
        self.logger.info('Loading image and mask')
        if isinstance(ImageFilePath,
                      six.string_types) and os.path.isfile(ImageFilePath):
            image = sitk.ReadImage(ImageFilePath)
        elif isinstance(ImageFilePath, sitk.SimpleITK.Image):
            image = ImageFilePath
        else:
            self.logger.warning(
                'Error reading image Filepath or SimpleITK object')
            return None, None  # this function is expected to always return a tuple of 2 elements

        if isinstance(MaskFilePath,
                      six.string_types) and os.path.isfile(MaskFilePath):
            mask = sitk.ReadImage(MaskFilePath)
        elif isinstance(MaskFilePath, sitk.SimpleITK.Image):
            mask = MaskFilePath
        else:
            self.logger.warning(
                'Error reading mask Filepath or SimpleITK object')
            return None, None  # this function is expected to always return a tuple of 2 elements

        # This point is only reached if image and mask loaded correctly
        if self.settings['normalize']:
            image = imageoperations.normalizeImage(
                image, self.settings['normalizeScale'],
                self.settings['removeOutliers'])

        if self.settings['interpolator'] is not None and self.settings[
                'resampledPixelSpacing'] is not None:
            image, mask = imageoperations.resampleImage(
                image, mask, self.settings['resampledPixelSpacing'],
                self.settings['interpolator'], self.settings['label'],
                self.settings['padDistance'])
        elif self.settings['preCrop']:
            bb, correctedMask = imageoperations.checkMask(
                image, mask, **self.settings)
            if correctedMask is not None:
                # Update the mask if it had to be resampled
                mask = correctedMask
            if bb is None:
                # Mask checks failed
                return None, None
            image, mask = imageoperations.cropToTumorMask(
                image, mask, bb, self.settings['padDistance'])

        return image, mask
コード例 #2
0
ファイル: testUtils.py プロジェクト: vnarayan13/pyradiomics
    def setFeatureClassAndTestCase(self, className, testCase):
        """
    Set testing suite to specified testCase and feature class. Throws an assertion error if either class or test case
    are not recognized. These have to be set here together, as the settings with which the test case has to be loaded
    are defined per feature class in the baseline (extracted from provenance information).

    Only (re)loads an image/mask if the test case has changed, or the change of feature class causes a change in test
    settings.

    If feature class and test case are unchanged, nothing is reloaded and function returns False. If either feature
    class or test case is changed, function returns True.
    """
        if self._featureClassName == className and self._testCase == testCase:
            return False

        # First set featureClass if necessary, because if settings have changed, testCase needs te be reloaded
        if self._featureClassName != className:
            self._logger.debug('Setting feature class name to %s', className)
            assert className in self.getFeatureClasses()

            self._featureClassName = className

            # Check if test settings have changed
            if self._kwargs != self.getBaselineSettings(className, testCase):
                self._kwargs = self.getBaselineSettings(className, testCase)
                self._testCase = None  # forces image to be reloaded (as settings have changed)

        # Next, set testCase if necessary
        if self._testCase != testCase:
            self._logger.info("Reading the image and mask for test case %s",
                              testCase)
            assert testCase in self.getTestCases()
            self._testedSet.add(testCase)

            imageName = str(
                os.path.join(self._dataDir, testCase + '_image.nrrd'))
            maskName = str(
                os.path.join(self._dataDir, testCase + '_label.nrrd'))

            self._image = sitk.ReadImage(imageName)
            self._mask = sitk.ReadImage(maskName)

            interpolator = self._kwargs.get('interpolator', sitk.sitkBSpline)
            resampledPixelSpacing = self._kwargs.get('resampledPixelSpacing',
                                                     None)

            if interpolator is not None and resampledPixelSpacing is not None:
                self._image, self._mask = imageoperations.resampleImage(
                    self._image, self._mask, resampledPixelSpacing,
                    interpolator, self._kwargs.get('label', 1),
                    self._kwargs.get('padDistance', 5))
            bb = imageoperations.checkMask(self._image, self._mask)
            self._image, self._mask = imageoperations.cropToTumorMask(
                self._image, self._mask, bb, self._kwargs.get('label', 1))
            self._testCase = testCase

        return True
コード例 #3
0
    def loadImage(self, ImageFilePath, MaskFilePath):
        """
    Preprocess the image and labelmap.
    If ImageFilePath is a string, it is loaded as SimpleITK Image and assigned to image,
    if it already is a SimpleITK Image, it is just assigned to image.
    All other cases are ignored (nothing calculated).
    Equal approach is used for assignment of mask using MaskFilePath.

    If normalizing is enabled image is first normalized before any resampling is applied.

    If resampling is enabled, both image and mask are resampled and cropped to the tumor mask (with additional
    padding as specified in padDistance) after assignment of image and mask.
    """
        if isinstance(ImageFilePath,
                      six.string_types) and os.path.exists(ImageFilePath):
            image = sitk.ReadImage(ImageFilePath)
        elif isinstance(ImageFilePath, sitk.SimpleITK.Image):
            image = ImageFilePath
        else:
            self.logger.warning(
                'Error reading image Filepath or SimpleITK object')
            if self.kwargs['verbose']:
                print("Error reading image Filepath or SimpleITK object")
            image = None

        if isinstance(MaskFilePath,
                      six.string_types) and os.path.exists(MaskFilePath):
            mask = sitk.ReadImage(MaskFilePath)
        elif isinstance(MaskFilePath, sitk.SimpleITK.Image):
            mask = MaskFilePath
        else:
            self.logger.warning(
                'Error reading mask Filepath or SimpleITK object')
            if self.kwargs['verbose']:
                print("Error reading mask Filepath or SimpleITK object")
            mask = None

        if image is not None and mask is not None:
            if self.kwargs['normalize']:
                image = imageoperations.normalizeImage(
                    image, self.kwargs['normalizeScale'],
                    self.kwargs['removeOutliers'])

            if self.kwargs['interpolator'] is not None and self.kwargs[
                    'resampledPixelSpacing'] is not None:
                image, mask = imageoperations.resampleImage(
                    image, mask, self.kwargs['resampledPixelSpacing'],
                    self.kwargs['interpolator'], self.kwargs['label'],
                    self.kwargs['padDistance'])

        return image, mask
コード例 #4
0
def demo():
    imageName, maskName = getTestCase('brain1')
    image = sitk.ReadImage(imageName)
    mask = sitk.ReadImage(maskName)
    settings = {
        'binWidth': 25,
        'interpolator': sitk.sitkBSpline,
        'resampledPixelSpacing': None
    }

    #
    # If enabled, resample image (resampled image is automatically cropped.
    #
    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)

    bb, correctedMask = imageoperations.checkMask(image, mask)
    if correctedMask is not None:
        mask = correctedMask
    image, mask = imageoperations.cropToTumorMask(image, mask, bb)
    ###
    firstOrderFeatures = firstorder.RadiomicsFirstOrder(
        image, mask, **settings)
    results = firstOrderFeatures.execute()
    print(results)
    ###
    shapeFeatures = shape.RadiomicsShape(image, mask, **settings)
    shapeFeatures.enableAllFeatures()
    results = shapeFeatures.execute()
    ###
    glcmFeatures = glcm.RadiomicsGLCM(image, mask, **settings)
    glcmFeatures.enableAllFeatures()
    results = glcmFeatures.execute()
    ###
    glrlmFeatures = glrlm.RadiomicsGLRLM(image, mask, **settings)
    glrlmFeatures.enableAllFeatures()
    results = glrlmFeatures.execute()
    ###
    glszmFeatures = glszm.RadiomicsGLSZM(image, mask, **settings)
    glszmFeatures.enableAllFeatures()
    results = glszmFeatures.execute()
コード例 #5
0
ファイル: helloResampling.py プロジェクト: zymale/pyradiomics
#!/usr/bin/env python

import sys

import SimpleITK as sitk

from radiomics import imageoperations

image = sitk.ReadImage(sys.argv[1])
mask = sitk.ReadImage(sys.argv[2])

# Resamples and crops onto bounding box defined by the label
(ii, im) = imageoperations.resampleImage(image,
                                         mask,
                                         resampledImageSpaceing=[2, 2, 2],
                                         label=1,
                                         padDistance=5)

sitk.WriteImage(ii, sys.argv[3])
sitk.WriteImage(im, sys.argv[4])
コード例 #6
0
    def loadImage(self, ImageFilePath, MaskFilePath):
        """
    Preprocess the image and labelmap.
    If ImageFilePath is a string, it is loaded as SimpleITK Image and assigned to image,
    if it already is a SimpleITK Image, it is just assigned to image.
    All other cases are ignored (nothing calculated).
    Equal approach is used for assignment of mask using MaskFilePath.

    If normalizing is enabled image is first normalized before any resampling is applied.

    If resampling is enabled, both image and mask are resampled and cropped to the tumor mask (with additional
    padding as specified in padDistance) after assignment of image and mask.
    """
        normalize = self.settings.get('normalize', False)
        interpolator = self.settings.get('interpolator')
        resampledPixelSpacing = self.settings.get('resampledPixelSpacing')
        preCrop = self.settings.get('preCrop', False)
        label = self.settings.get('label', 1)

        self.logger.info('Loading image and mask')
        if isinstance(ImageFilePath,
                      six.string_types) and os.path.isfile(ImageFilePath):
            image = sitk.ReadImage(ImageFilePath)
        elif isinstance(ImageFilePath, sitk.SimpleITK.Image):
            image = ImageFilePath
        else:
            raise ValueError(
                'Error reading image Filepath or SimpleITK object')

        if isinstance(MaskFilePath,
                      six.string_types) and os.path.isfile(MaskFilePath):
            mask = sitk.ReadImage(MaskFilePath, sitk.sitkUInt32)
        elif isinstance(MaskFilePath, sitk.SimpleITK.Image):
            mask = sitk.Cast(MaskFilePath, sitk.sitkUInt32)
        else:
            raise ValueError('Error reading mask Filepath or SimpleITK object')

        if self.generalInfo is not None:
            self.generalInfo.addImageElements(image)
            # Do not include the image here, as the overlap between image and mask have not been checked
            # It is therefore possible that image and mask do not align, or even have different sizes.
            self.generalInfo.addMaskElements(None, mask, label)

        # This point is only reached if image and mask loaded correctly
        if normalize:
            image = imageoperations.normalizeImage(image, **self.settings)

        if interpolator is not None and resampledPixelSpacing is not None:
            image, mask = imageoperations.resampleImage(
                image, mask, **self.settings)
            if self.generalInfo is not None:
                self.generalInfo.addImageElements(image, 'interpolated')
                self.generalInfo.addMaskElements(image, mask,
                                                 self.settings.get('label', 1),
                                                 'interpolated')

        elif preCrop:
            bb, correctedMask = imageoperations.checkMask(
                image, mask, **self.settings)
            if correctedMask is not None:
                # Update the mask if it had to be resampled
                mask = correctedMask
            if bb is None:
                # Mask checks failed
                raise ValueError('Mask checks failed during pre-crop')

            image, mask = imageoperations.cropToTumorMask(
                image, mask, bb, **self.settings)

        return image, mask
コード例 #7
0
    def loadImage(ImageFilePath,
                  MaskFilePath,
                  otherImageFilePath,
                  generalInfo=None,
                  **kwargs):
        """
    Load and pre-process the image and labelmap.
    If ImageFilePath is a string, it is loaded as SimpleITK Image and assigned to ``image``,
    if it already is a SimpleITK Image, it is just assigned to ``image``.
    All other cases are ignored (nothing calculated).
    Equal approach is used for assignment of ``mask`` using MaskFilePath. If necessary, a segmentation object (i.e. mask
    volume with vector-image type) is then converted to a labelmap (=scalar image type). Data type is forced to UInt32.
    See also :py:func:`~imageoperations.getMask()`.

    If normalizing is enabled image is first normalized before any resampling is applied.

    If resampling is enabled, both image and mask are resampled and cropped to the tumor mask (with additional
    padding as specified in padDistance) after assignment of image and mask.

    :param ImageFilePath: SimpleITK.Image object or string pointing to SimpleITK readable file representing the image
                          to use.
    :param MaskFilePath: SimpleITK.Image object or string pointing to SimpleITK readable file representing the mask
                         to use.
    :param generalInfo: GeneralInfo Object. If provided, it is used to store diagnostic information of the
                        pre-processing.
    :param kwargs: Dictionary containing the settings to use for this particular image type.
    :return: 2 SimpleITK.Image objects representing the loaded image and mask, respectively.
    """
        global logger

        normalize = kwargs.get('normalize', False)
        interpolator = kwargs.get('interpolator')
        resampledPixelSpacing = kwargs.get('resampledPixelSpacing')
        preCrop = kwargs.get('preCrop', False)
        label = kwargs.get('label', 1)

        logger.info('Loading image and mask')
        if isinstance(ImageFilePath,
                      six.string_types) and os.path.isfile(ImageFilePath):
            image = sitk.ReadImage(ImageFilePath)
        elif isinstance(ImageFilePath, sitk.SimpleITK.Image):
            image = ImageFilePath
        else:
            raise ValueError(
                'Error reading image Filepath or SimpleITK object')

        if isinstance(MaskFilePath,
                      six.string_types) and os.path.isfile(MaskFilePath):
            mask = sitk.ReadImage(MaskFilePath)
        elif isinstance(MaskFilePath, sitk.SimpleITK.Image):
            mask = MaskFilePath
        else:
            raise ValueError('Error reading mask Filepath or SimpleITK object')

        # Read other image for washin
        if otherImageFilePath is not None:
            if isinstance(
                    otherImageFilePath,
                    six.string_types) and os.path.isfile(otherImageFilePath):
                imageOther = sitk.ReadImage(otherImageFilePath)
            elif isinstance(otherImageFilePath, sitk.SimpleITK.Image):
                imageOther = otherImageFilePath
            else:
                raise ValueError(
                    'Error reading image Filepath or SimpleITK object')

            # Align input types
            caster = sitk.CastImageFilter()
            caster.SetOutputPixelType(sitk.sitkFloat64)
            image = caster.Execute(image)
            imageOther = caster.Execute(imageOther)

            # t1 - t0
            f_subtract = sitk.SubtractImageFilter()
            wash = f_subtract.Execute(imageOther, image)
            # (t1 - t0) / t0
            f_divide = sitk.DivideImageFilter()
            wash = f_divide.Execute(wash, image)

            # Replace max Values with 0
            f_less = sitk.LessEqualImageFilter()
            value_mask = f_less.Execute(wash, sys.float_info.max / 2)
            f_mask = sitk.MaskImageFilter()
            image = f_mask.Execute(wash, value_mask)

        # process the mask
        mask = imageoperations.getMask(mask, **kwargs)

        if generalInfo is not None:
            generalInfo.addImageElements(image)
            # Do not include the image here, as the overlap between image and mask have not been checked
            # It is therefore possible that image and mask do not align, or even have different sizes.
            generalInfo.addMaskElements(None, mask, label)

        # This point is only reached if image and mask loaded correctly
        if normalize:
            image = imageoperations.normalizeImage(image, **kwargs)

        if interpolator is not None and resampledPixelSpacing is not None:
            image, mask = imageoperations.resampleImage(image, mask, **kwargs)
            if generalInfo is not None:
                generalInfo.addImageElements(image, 'interpolated')
                generalInfo.addMaskElements(image, mask, label, 'interpolated')

        elif preCrop:
            bb, correctedMask = imageoperations.checkMask(
                image, mask, **kwargs)
            if correctedMask is not None:
                # Update the mask if it had to be resampled
                mask = correctedMask
            if bb is None:
                # Mask checks failed
                raise ValueError('Mask checks failed during pre-crop')

            image, mask = imageoperations.cropToTumorMask(
                image, mask, bb, **kwargs)

        return image, mask
コード例 #8
0
    def setFeatureClassAndTestCase(self, className, test):
        """
    Set testing suite to specified testCase and feature class. Throws an assertion error if either class or test case
    are not recognized. These have to be set here together, as the settings with which the test case has to be loaded
    are defined per feature class in the baseline (extracted from provenance information).

    Only (re)loads an image/mask if the test case has changed, or the change of feature class causes a change in test
    settings.

    If feature class and test case are unchanged, nothing is reloaded and function returns False. If either feature
    class or test case is changed, function returns True.
    """
        global TEST_CASES
        if self._featureClassName == className and self._test == test:
            return False

        self._test = test
        self._testedSet.add(self._test)

        # First set featureClass if necessary, because if settings have changed, testCase needs te be reloaded
        if self._featureClassName != className:
            self._logger.debug('Setting feature class name to %s', className)
            assert className in self._baseline.keys(
            )  # Check if a baseline has been read for this class

            self._featureClassName = className

            # Check if test settings have changed
            if self._current_config != self._baseline[className].getTestConfig(
                    test):
                self._current_config = self._baseline[className].getTestConfig(
                    test)
                self._testCase = None  # forces image to be reloaded (as settings have changed)

        # Next, set testCase if necessary
        if self._testCase != self._current_config['TestCase']:
            self._testCase = self._current_config['TestCase']
            self._logger.info("Reading the image and mask for test case %s",
                              self._testCase)
            assert self._current_config['TestCase'] in TEST_CASES

            imageName, maskName = getTestCase(self._testCase)

            assert imageName is not None
            assert maskName is not None

            self._image = sitk.ReadImage(imageName)
            self._mask = sitk.ReadImage(maskName)

            if 'ImageHash' in self._current_config:
                assert sitk.Hash(
                    self._image) == self._current_config['ImageHash']
            if 'MaskHash' in self._current_config:
                assert sitk.Hash(
                    self._mask) == self._current_config['MaskHash']

            settings = self._current_config.get('Settings', {})

            interpolator = settings.get('interpolator', sitk.sitkBSpline)
            resampledPixelSpacing = settings.get('resampledPixelSpacing', None)

            if interpolator is not None and resampledPixelSpacing is not None:
                self._image, self._mask = imageoperations.resampleImage(
                    self._image, self._mask, resampledPixelSpacing,
                    interpolator, settings.get('label', 1),
                    settings.get('padDistance', 5))
            self._bb, correctedMask = imageoperations.checkMask(
                self._image, self._mask, **settings)
            if correctedMask is not None:
                self._mask = correctedMask

            self._imageType = None

        return True
コード例 #9
0
applyLog = False
applyWavelet = False

# Setting for the feature calculation.
# Currently, resampling is disabled.
# Can be enabled by setting 'resampledPixelSpacing' to a list of 3 floats (new voxel size in mm for x, y and z)
kwargs = {'binWidth': 25,
          'interpolator': sitk.sitkBSpline,
          'resampledPixelSpacing': None}

#
# If enabled, resample image (resampled image is automatically cropped.
# If resampling is not enabled, crop image instead
#
if kwargs['interpolator'] is not None and kwargs['resampledPixelSpacing'] is not None:
  image, mask = imageoperations.resampleImage(image, mask, kwargs['resampledPixelSpacing'], kwargs['interpolator'])
else:
  bb, correctedMask = imageoperations.checkMask(image, mask)
  if correctedMask is not None:
    mask = correctedMask
  image, mask = imageoperations.cropToTumorMask(image, mask, bb)

#
# Show the first order feature calculations
#
firstOrderFeatures = firstorder.RadiomicsFirstOrder(image, mask, **kwargs)

firstOrderFeatures.enableFeatureByName('Mean', True)
# firstOrderFeatures.enableAllFeatures()

print('Will calculate the following first order features: ')
コード例 #10
0
def calc_radio_fea(img: np.ndarray, mask: np.ndarray) -> List[np.ndarray]:
    assert type(
        img
    ) == np.ndarray, f"TypeError, expected np.ndarray but Got {type(img)}"
    assert img.shape == mask.shape, f"SizeError, expected to be same, but Got {img.shape} and {mask.shape}"

    image = sitk.GetImageFromArray(img)
    mask = sitk.GetImageFromArray(mask)

    # Setting for the feature calculation.
    # Currently, resampling is disabled.
    # Can be enabled by setting 'resampledPixelSpacing' to a list of 3 floats (new voxel size in mm for x, y and z)
    settings = {
        'binWidth': 25,
        'interpolator': sitk.sitkBSpline,
        'resampledPixelSpacing': None
    }
    #
    # If enabled, resample image (resampled image is automatically cropped.
    #
    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)

    bb, correctedMask = imageoperations.checkMask(image, mask)
    if correctedMask is not None:
        mask = correctedMask
    image, mask = imageoperations.cropToTumorMask(image, mask, bb)
    results_collect = dict()
    results_np = list()
    # Fisrt order
    firstOrderFeatures = firstorder.RadiomicsFirstOrder(
        image, mask, **settings)
    # firstOrderFeatures.enableFeatureByName('Mean', True)
    firstOrderFeatures.enableAllFeatures()
    results: dict = firstOrderFeatures.execute()  # dict()
    # results_collect['FirstOrder'] = results
    results_np.append(np.array([value for key, value in results.items()]))
    #
    shapeFeatures = shape.RadiomicsShape(image, mask, **settings)
    shapeFeatures.enableAllFeatures()
    results = shapeFeatures.execute()
    # results_collect['ShapeFeature'] = results
    results_np.append(np.array([value for key, value in results.items()]))
    ###
    glcmFeatures = glcm.RadiomicsGLCM(image, mask, **settings)
    glcmFeatures.enableAllFeatures()
    results = glcmFeatures.execute()
    # results_collect['GLCM'] = results
    results_np.append(np.array([value for key, value in results.items()]))
    ###
    glrlmFeatures = glrlm.RadiomicsGLRLM(image, mask, **settings)
    glrlmFeatures.enableAllFeatures()
    results = glrlmFeatures.execute()
    # results_collect['GLRLM'] = results
    results_np.append(np.array([value for key, value in results.items()]))
    ###
    glszmFeatures = glszm.RadiomicsGLSZM(image, mask, **settings)
    glszmFeatures.enableAllFeatures()
    results = glszmFeatures.execute()
    # results_collect['GLSZM'] = results
    results_np.append(np.array([value for key, value in results.items()]))

    gldmFeatures = gldm.RadiomicsGLDM(image, mask, **settings)
    gldmFeatures.enableAllFeatures()
    results = gldmFeatures.execute()
    results_np.append(np.array([value for key, value in results.items()]))

    return results_np
コード例 #11
0
import sys

import SimpleITK as sitk

from radiomics import imageoperations

image = sitk.ReadImage(sys.argv[1])
mask = sitk.ReadImage(sys.argv[2])

(ii, im) = imageoperations.resampleImage(image, mask, [2, 2, 2])

sitk.WriteImage(ii, sys.argv[3])
sitk.WriteImage(im, sys.argv[4])
コード例 #12
0
ファイル: service.py プロジェクト: pyplati/platipy
def pyradiomics_extractor(data_objects, working_dir, settings):
    """Run to extract radiomics from data objects

    Args:
        data_objects (list): List of data objects to process
        working_dir (str): Path to directory used for working
        settings ([type]): The settings to use for processing radiomics

    Returns:
        list: List of output data objects
    """

    logger.info("Running PyRadiomics Extract")
    logger.info("Using settings: " + str(settings))

    pyrad_settings = settings["pyradiomics_settings"]

    # If no Radiomics are supplied then extract for all first order radiomics
    if len(settings["radiomics"].keys()) == 0:
        features = firstorder.RadiomicsFirstOrder.getFeatureNames()
        settings["radiomics"] = {"firstorder": [f for f in features if not features[f]]}

    results = None
    meta_data_cols = [("", "Contour")]
    for data_obj in data_objects:

        try:
            if len(data_obj.children) > 0:

                logger.info("Running on data object: " + data_obj.path)

                # Read the image series
                load_path = data_obj.path
                if data_obj.type == "DICOM":
                    load_path = sitk.ImageSeriesReader().GetGDCMSeriesFileNames(data_obj.path)

                # Children of Image Data Object are masks, compute PyRadiomics for all of them!
                output_frame = pd.DataFrame()
                for child_obj in data_obj.children:

                    contour_name = child_obj.path.split("/")[-1].split(".")[0]
                    if len(settings["contours"]) > 0 and not contour_name in settings["contours"]:
                        # If a contour list is provided and this contour isn't in the list then
                        # skip it
                        logger.debug("Skipping Contour: ", contour_name)
                        continue

                    # Reload the image for each new contour in case resampling is occuring,
                    # should start fresh each time.
                    image = sitk.ReadImage(load_path)
                    mask = sitk.ReadImage(child_obj.path)

                    logger.debug("Image Origin: " + str(image.GetOrigin()))
                    logger.debug("Mask Origin: " + str(mask.GetOrigin()))
                    logger.debug("Image Direction: " + str(image.GetDirection()))
                    logger.debug("Mask Direction: " + str(mask.GetDirection()))
                    logger.debug("Image Size: " + str(image.GetSize()))
                    logger.debug("Mask Size: " + str(mask.GetSize()))

                    logger.info(child_obj.path)

                    interpolator = pyrad_settings.get("interpolator")
                    resample_pixel_spacing = pyrad_settings.get("resampledPixelSpacing")

                    if settings["resample_to_image"]:
                        logger.info("Will resample to spacing of image")
                        resample_pixel_spacing = list(image.GetSpacing())
                        pyrad_settings["resampledPixelSpacing"] = resample_pixel_spacing

                    if interpolator is not None and resample_pixel_spacing is not None:
                        logger.info("Resampling Image and Mask")
                        image, mask = imageoperations.resampleImage(image, mask, **pyrad_settings)

                    # output[contour_name] = {"Contour": contour_name}
                    df_contour = pd.DataFrame()

                    logger.info("Computing Radiomics for contour: {0}", contour_name)

                    for rad in settings["radiomics"].keys():

                        logger.info("Computing {0} radiomics".format(rad))

                        if rad not in AVAILABLE_RADIOMICS.keys():
                            logger.warning("Radiomic Class not found: {0}", rad)
                            continue

                        radiomics_obj = AVAILABLE_RADIOMICS[rad]

                        features = radiomics_obj(image, mask, **pyrad_settings)

                        features.disableAllFeatures()

                        # All features seem to be computed if all are disabled (possible
                        # pyradiomics bug?). Skip if all features in a class are disabled.
                        if len(settings["radiomics"][rad]) == 0:
                            continue

                        for feature in settings["radiomics"][rad]:
                            try:
                                features.enableFeatureByName(feature, True)
                            except LookupError:
                                # Feature not available in this set
                                logger.warning("Feature not found: {0}", feature)

                        feature_result = features.execute()
                        feature_result = dict(
                            ((rad, key), value) for (key, value) in feature_result.items()
                        )
                        df_feature_result = pd.DataFrame(feature_result, index=[contour_name])

                        # Merge the results
                        df_contour = pd.concat([df_contour, df_feature_result], axis=1)

                    df_contour[("", "Contour")] = contour_name
                    output_frame = pd.concat([output_frame, df_contour])

                    # Add the meta data for this contour if there is any
                    if child_obj.meta_data:
                        for key in child_obj.meta_data:

                            col_key = ("", key)

                            output_frame[col_key] = child_obj.meta_data[key]

                            if col_key not in meta_data_cols:
                                meta_data_cols.append(col_key)

                # Add Image Series Data Object's Meta Data to the table
                if data_obj.meta_data:
                    for key in data_obj.meta_data.keys():

                        col_key = ("", key)

                        output_frame[col_key] = pd.Series(
                            [data_obj.meta_data[key] for p in range(len(output_frame.index))],
                            index=output_frame.index,
                        )

                        if col_key not in meta_data_cols:
                            meta_data_cols.append(col_key)

                if results is None:
                    results = output_frame
                else:
                    results = results.append(output_frame)
        except Exception as exception:  # pylint: disable=broad-except
            logger.error("An Error occurred while computing the Radiomics: {0}", exception)

    # Set the order of the columns output
    cols = results.columns.tolist()
    new_cols = list(meta_data_cols)
    new_cols += [c for c in cols if not c in meta_data_cols]
    results = results[new_cols]

    # Write output to file
    output_file = os.path.join(working_dir, "output.csv")
    results = results.reset_index()
    results = results.drop(columns=["index"])
    results.to_csv(output_file)
    logger.info("Radiomics written to {0}".format(output_file))

    # Create the output Data Object and add it to output_objects
    data_object = DataObject(type="FILE", path=output_file)
    output_objects = [data_object]

    return output_objects
コード例 #13
0
# Setting for the feature calculation.
# Currently, resampling is disabled.
# Can be enabled by setting 'resampledPixelSpacing' to a list of 3 floats (new voxel size in mm for x, y and z)
settings = {
    'binWidth': 25,
    'interpolator': sitk.sitkBSpline,
    'resampledPixelSpacing': None
}

#
# If enabled, resample image (resampled image is automatically cropped.
#
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)

bb, correctedMask = imageoperations.checkMask(image, mask)
if correctedMask is not None:
    mask = correctedMask
image, mask = imageoperations.cropToTumorMask(image, mask, bb)

#
# Show the first order feature calculations
#
firstOrderFeatures = firstorder.RadiomicsFirstOrder(image, mask, **settings)

# firstOrderFeatures.enableFeatureByName('Mean', True)
firstOrderFeatures.enableAllFeatures()

# print('Will calculate the following first order features: ')
コード例 #14
0
def features_extractor(patients_nrrd_path, valid_IDs, applyLog = False, applyWavelet = False):
    feature_vectors = {}
    cnt = 0
    for case_id in valid_IDs:
        feature_vectors[case_id] = {}
        cnt += 1
        # try:
        ct_nrrd_path = os.path.join(patients_nrrd_path,case_id, "image.nrrd")
        ss_nrrd_path = os.path.join(patients_nrrd_path,case_id, "mask.nrrd")
        print("Reading ct image")
        image = sitk.ReadImage(ct_nrrd_path)
        # image, header = nrrd.read(ct_nrrd_path)
        print("Reading roi mask")
        mask = sitk.ReadImage(ss_nrrd_path)
        # mask, header = nrrd.read(ss_nrrd_path)
        print("Getting ct image array")
        image_array = sitk.GetArrayFromImage(image)
        print("Getting roi mask array")
        mask_array = sitk.GetArrayFromImage(mask)
        print(image_array.shape, mask_array.shape)
        # simple_plot_nrrd(image_array, mask_array, sliceNumber=75, plotSrc='sitk')
        print (cnt, "_ Calculating features: ",case_id)   

        settings = {'binWidth': 25,
                'interpolator': sitk.sitkBSpline,
                'resampledPixelSpacing': None}
        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)
        bb, correctedMask = imageoperations.checkMask(image, mask)
        if correctedMask is not None:
          mask = correctedMask
        image, mask = imageoperations.cropToTumorMask(image, mask, bb)
        
        firstOrderFeatures = firstorder.RadiomicsFirstOrder(image, mask, **settings)
        # firstOrderFeatures.enableFeatureByName('Mean', True)
        firstOrderFeatures.enableAllFeatures()

        # print('Will calculate the following first order features: ')
        # for f in firstOrderFeatures.enabledFeatures.keys():
        #   print('  ', f)
        #   print(getattr(firstOrderFeatures, 'get%sFeatureValue' % f).__doc__)

        # print('Calculating first order features...')
        results = firstOrderFeatures.execute()
        # print('done')

        print('Calculated first order features: ')
        for (key, val) in six.iteritems(results):
            firstOrderFeatureName = '%s_%s' % ('firstOrder', key)
            if firstOrderFeatureName not in feature_vectors[case_id]:
                feature_vectors[case_id][firstOrderFeatureName] = val
            else:
                print('Error: firstOrder key existing! %s'%firstOrderFeatureName)
                # break
            # print('  ', key, ':', val)

        #
        # Show Shape features
        #

        shapeFeatures = shape.RadiomicsShape(image, mask, **settings)
        shapeFeatures.enableAllFeatures()

        # print('Will calculate the following Shape features: ')
        # for f in shapeFeatures.enabledFeatures.keys():
        #   print('  ', f)
        #   print(getattr(shapeFeatures, 'get%sFeatureValue' % f).__doc__)

        # print('Calculating Shape features...')
        results = shapeFeatures.execute()
        # print('done')

        print('Calculated Shape features: ')
        for (key, val) in six.iteritems(results):
            ShapeFeatureName = '%s_%s' % ('Shape', key)
            if ShapeFeatureName not in feature_vectors[case_id]:
                feature_vectors[case_id][ShapeFeatureName] = val
            else:
                print('Error: shape key existing! %s'%ShapeFeatureName)
                # break
            # print('  ', key, ':', val)

        #
        # Show GLCM features: Gray Level Co-occurrence Matrix (GLCM) Features
        #
        glcmFeatures = glcm.RadiomicsGLCM(image, mask, **settings)
        glcmFeatures.enableAllFeatures()

        # print('Will calculate the following GLCM features: ')
        # for f in glcmFeatures.enabledFeatures.keys():
        #   print('  ', f)
        #   print(getattr(glcmFeatures, 'get%sFeatureValue' % f).__doc__)

        # print('Calculating GLCM features...')
        results = glcmFeatures.execute()
        # print('done')

        print('Calculated GLCM features: ')
        for (key, val) in six.iteritems(results):
            GLCMFeatureName = '%s_%s' % ('GLCM', key)
            if GLCMFeatureName not in feature_vectors[case_id]:
                feature_vectors[case_id][GLCMFeatureName] = val
            else:
                print('Error: GLCM key existing! %s'%GLCMFeatureName)
                # break
            # print('  ', key, ':', val)



        #
        # Show GLSZM features; Gray Level Size Zone Matrix (GLSZM) Features
        #
        glszmFeatures = glszm.RadiomicsGLSZM(image, mask, **settings)
        glszmFeatures.enableAllFeatures()

        # print('Will calculate the following GLSZM features: ')
        # for f in glszmFeatures.enabledFeatures.keys():
        #   print('  ', f)
        #   print(getattr(glszmFeatures, 'get%sFeatureValue' % f).__doc__)

        # print('Calculating GLSZM features...')
        results = glszmFeatures.execute()
        print('done')

        print('Calculated GLSZM features: ')
        for (key, val) in six.iteritems(results):
            GLSZMFeatureName = '%s_%s' % ('GLSZM', key)
            if GLSZMFeatureName not in feature_vectors[case_id]:
                feature_vectors[case_id][GLSZMFeatureName] = val
            else:
                print('Error: GLSZM key existing! %s'%GLSZMFeatureName)
                # break
            # print('  ', key, ':', val)


        #
        # Show GLRLM features; Gray Level Run Length Matrix (GLRLM) Features
        #
        glrlmFeatures = glrlm.RadiomicsGLRLM(image, mask, **settings)
        glrlmFeatures.enableAllFeatures()

        # print('Will calculate the following GLRLM features: ')
        # for f in glrlmFeatures.enabledFeatures.keys():
        #   print('  ', f)
        #   print(getattr(glrlmFeatures, 'get%sFeatureValue' % f).__doc__)

        # print('Calculating GLRLM features...')
        results = glrlmFeatures.execute()
        # print('done')

        print('Calculated GLRLM features: ')
        for (key, val) in six.iteritems(results):
            GLRLMFeatureName = '%s_%s' % ('GLRLM', key)
            if GLRLMFeatureName not in feature_vectors[case_id]:
                feature_vectors[case_id][GLRLMFeatureName] = val
            else:
                print('Error: GLRLM key existing! %s'%GLRLMFeatureName)
                # break
            # print('  ', key, ':', val)

        #
        # Show NGTDM features; Neighbouring Gray Tone Difference Matrix (NGTDM) Features
        #
        ngtdmFeatures = ngtdm.RadiomicsNGTDM(image, mask, **settings)
        ngtdmFeatures.enableAllFeatures()

        # print('Will calculate the following NGTDM features: ')
        # for f in ngtdmFeatures.enabledFeatures.keys():
        #   print('  ', f)
        #   print(getattr(ngtdmFeatures, 'get%sFeatureValue' % f).__doc__)

        # print('Calculating NGTDM features...')
        results = ngtdmFeatures.execute()
        # print('done')

        print('Calculated NGTDM features: ')
        for (key, val) in six.iteritems(results):
            NGTDMFeatureName = '%s_%s' % ('NGTDM', key)
            if NGTDMFeatureName not in feature_vectors[case_id]:
                feature_vectors[case_id][NGTDMFeatureName] = val
            else:
                print('Error: NGTDM key existing! %s'%NGTDMFeatureName)
                # break
            # print('  ', key, ':', val)

        #
        # Show GLDM features; Gray Level Dependence Matrix (GLDM) Features
        #
        gldmFeatures = gldm.RadiomicsGLDM(image, mask, **settings)
        gldmFeatures.enableAllFeatures()

        # print('Will calculate the following GLDM features: ')
        # for f in gldmFeatures.enabledFeatures.keys():
        #   print('  ', f)
        #   print(getattr(gldmFeatures, 'get%sFeatureValue' % f).__doc__)

        # print('Calculating GLDM features...')
        results = gldmFeatures.execute()
        # print('done')

        print('Calculated GLDM features: ')
        for (key, val) in six.iteritems(results):
            GLDMFeatureName = '%s_%s' % ('GLDM', key)
            if GLDMFeatureName not in feature_vectors[case_id]:
                feature_vectors[case_id][GLDMFeatureName] = val
            else:
                print('Error: GLDM key existing! %s'%GLDMFeatureName)
                # break
            # print('  ', key, ':', val)


        #
        # Show FirstOrder features, calculated on a LoG filtered image
        #
        if applyLog:
          sigmaValues = np.arange(5., 0., -.5)[::1]
          for logImage, imageTypeName, inputKwargs in imageoperations.getLoGImage(image, mask, sigma=sigmaValues):
            logFirstorderFeatures = firstorder.RadiomicsFirstOrder(logImage, mask, **inputKwargs)
            logFirstorderFeatures.enableAllFeatures()
            results = logFirstorderFeatures.execute()
            for (key, val) in np.iteritems(results):
                laplacianFeatureName = '%s_%s' % (imageTypeName, key)
                if laplacianFeatureName not in feature_vectors[case_id]:
                    feature_vectors[case_id][laplacianFeatureName] = val
                else:
                    print('Error: LoG key existing! %s'%laplacianFeatureName)
                    # break
                # print('  ', laplacianFeatureName, ':', val)
        #
        # Show FirstOrder features, calculated on a wavelet filtered image
        #
        if applyWavelet:
          for decompositionImage, decompositionName, inputKwargs in imageoperations.getWaveletImage(image, mask):
            waveletFirstOrderFeaturs = firstorder.RadiomicsFirstOrder(decompositionImage, mask, **inputKwargs)
            waveletFirstOrderFeaturs.enableAllFeatures()
            results = waveletFirstOrderFeaturs.execute()
            print('Calculated firstorder features with wavelet ', decompositionName)
            for (key, val) in six.iteritems(results):
                waveletFeatureName = '%s_%s' % (str(decompositionName), key)
                if waveletFeatureName not in feature_vectors[case_id]:
                    feature_vectors[case_id][waveletFeatureName] = val
                else:
                    print('Error: wavelet key existing! %s'%waveletFeatureName)
                    # break
                # print('  ', waveletFeatureName, ':', val)

        mask = None
        image = None
    return feature_vectors
コード例 #15
0
#!/usr/bin/env python

import sys

import SimpleITK as sitk

from radiomics import imageoperations

image = sitk.ReadImage(sys.argv[1])
mask = sitk.ReadImage(sys.argv[2])

# Resamples and crops onto bounding box defined by the label
(ii, im) = imageoperations.resampleImage(image,
                                         mask, [2, 2, 2],
                                         label=1,
                                         padDistance=5)

sitk.WriteImage(ii, sys.argv[3])
sitk.WriteImage(im, sys.argv[4])