From 72ac3cbe9ac5912bfa7f64cc3e6cef2b136fdc9e Mon Sep 17 00:00:00 2001 From: Kevin Mader Date: Thu, 9 Feb 2017 11:49:57 +0100 Subject: [PATCH 1/6] making it python 3 compatible (https://github.com/Radiomics/pyradiomics/issues/178) without breaking the python 2 compatibility, adding the future imports to keep others clean and behavior particularly division consistent --- radiomics/__init__.py | 9 +++++++++ radiomics/_version.py | 2 +- radiomics/featureextractor.py | 22 ++++++++++++---------- radiomics/generalinfo.py | 5 +++-- radiomics/glszm.py | 6 ++++-- radiomics/imageoperations.py | 6 +++--- tests/testUtils.py | 11 ++++++----- tests/test_docstrings.py | 2 +- tests/test_features.py | 11 ++++++----- versioneer.py | 15 +++++++++++++-- 10 files changed, 58 insertions(+), 31 deletions(-) diff --git a/radiomics/__init__.py b/radiomics/__init__.py index 219f74e9..d7625fbd 100644 --- a/radiomics/__init__.py +++ b/radiomics/__init__.py @@ -1,9 +1,18 @@ +from __future__ import print_function, unicode_literals, division, absolute_import import sys if sys.version_info < (2, 6, 0): raise ImportError("pyradiomics > 0.9.7 requires python 2.6 or later") in_py3 = sys.version_info[0] > 2 +if in_py3: + c_str_type = str + safe_xrange = lambda x: iter(range(x)) +else: + c_str_type = basestring + safe_xrange = xrange + + import logging diff --git a/radiomics/_version.py b/radiomics/_version.py index c6491c5f..e406c78a 100644 --- a/radiomics/_version.py +++ b/radiomics/_version.py @@ -74,8 +74,8 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, assert isinstance(commands, list) p = None for c in commands: + dispcmd = str([c] + args) try: - dispcmd = str([c] + args) # remember shell=False, so use git.cmd on windows, not just git p = subprocess.Popen([c] + args, cwd=cwd, env=env, stdout=subprocess.PIPE, diff --git a/radiomics/featureextractor.py b/radiomics/featureextractor.py index bccdd46c..32fe1904 100644 --- a/radiomics/featureextractor.py +++ b/radiomics/featureextractor.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +from __future__ import print_function, unicode_literals, division, absolute_import import os import logging import collections @@ -9,7 +10,8 @@ import inspect import pykwalify.core import radiomics -from radiomics import base, imageoperations, generalinfo +from radiomics import base, imageoperations, generalinfo, c_str_type + class RadiomicsFeaturesExtractor: @@ -71,7 +73,7 @@ def __init__(self, *args, **kwargs): self.inputImages = {} self.enabledFeatures = {} - if len(args) == 1 and isinstance(args[0], basestring): + if len(args) == 1 and isinstance(args[0], c_str_type): self.loadParams(args[0]) else: # Set default settings and update with and changed settings contained in kwargs @@ -315,7 +317,7 @@ def execute(self, imageFilepath, maskFilepath, label=None): for feature in enabledFeatures: shapeClass.enableFeatureByName(feature) - if self.kwargs['verbose']: print "\t\tComputing shape" + if self.kwargs['verbose']: print("\t\tComputing shape") shapeClass.calculateFeatures() for (featureName, featureValue) in shapeClass.featureValues.iteritems(): newFeatureName = "original_shape_%s" % (featureName) @@ -323,7 +325,7 @@ def execute(self, imageFilepath, maskFilepath, label=None): # Make generators for all enabled input image types imageGenerators = [] - for imageType, customKwargs in self.inputImages.iteritems(): + for imageType, customKwargs in self.inputImages.items(): args = self.kwargs.copy() args.update(customKwargs) self.logger.info("Applying filter: '%s' with settings: %s" % (imageType, str(args))) @@ -348,22 +350,22 @@ def loadImage(self, ImageFilePath, MaskFilePath): If resampling is enabled, both image and mask are resampled and cropped to the tumormask (with additional padding as specified in padDistance) after assignment of image and mask. """ - if isinstance(ImageFilePath, basestring) and os.path.exists(ImageFilePath): + if isinstance(ImageFilePath, c_str_type) 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" + if self.kwargs['verbose']: print("Error reading image Filepath or SimpleITK object") image = None - if isinstance(MaskFilePath, basestring) and os.path.exists(MaskFilePath): + if isinstance(MaskFilePath, c_str_type) and os.path.exists(MaskFilePath): mask = sitk.ReadImage(MaskFilePath) elif isinstance(ImageFilePath, 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" + if self.kwargs['verbose']: print("Error reading mask Filepath or SimpleITK object") mask = None if self.kwargs['interpolator'] is not None and self.kwargs['resampledPixelSpacing'] is not None: @@ -398,7 +400,7 @@ def computeFeatures(self, image, mask, inputImageName, **kwargs): featureVector = collections.OrderedDict() # Calculate feature classes - for featureClassName, enabledFeatures in self.enabledFeatures.iteritems(): + for featureClassName, enabledFeatures in self.enabledFeatures.items(): # Handle calculation of shape features separately if featureClassName == 'shape': continue @@ -412,7 +414,7 @@ def computeFeatures(self, image, mask, inputImageName, **kwargs): for feature in enabledFeatures: featureClass.enableFeatureByName(feature) - if self.kwargs['verbose']: print "\t\tComputing %s" % (featureClassName) + if self.kwargs['verbose']: print("\t\tComputing %s" % (featureClassName)) featureClass.calculateFeatures() for (featureName, featureValue) in featureClass.featureValues.iteritems(): newFeatureName = "%s_%s_%s" % (inputImageName, featureClassName, featureName) diff --git a/radiomics/generalinfo.py b/radiomics/generalinfo.py index 04e966de..485ab35a 100644 --- a/radiomics/generalinfo.py +++ b/radiomics/generalinfo.py @@ -3,13 +3,14 @@ import numpy import SimpleITK as sitk import radiomics +from radiomics import c_str_type class GeneralInfo(): def __init__(self, imagePath, maskPath, resampledMask, kwargs, inputImages): self.logger = logging.getLogger(self.__module__) - if isinstance(imagePath, basestring): + if isinstance(imagePath, c_str_type): self.image = sitk.ReadImage(imagePath) elif isinstance(imagePath, sitk.Image): self.image = imagePath @@ -17,7 +18,7 @@ def __init__(self, imagePath, maskPath, resampledMask, kwargs, inputImages): self.logger.warning('Error reading image Filepath or SimpleITK object') self.image = None - if isinstance(maskPath, basestring): + if isinstance(maskPath, c_str_type): self.mask = sitk.ReadImage(maskPath) elif isinstance(maskPath, sitk.Image): self.mask = maskPath diff --git a/radiomics/glszm.py b/radiomics/glszm.py index b4539421..755701f0 100644 --- a/radiomics/glszm.py +++ b/radiomics/glszm.py @@ -1,10 +1,12 @@ +import sys import numpy import SimpleITK as sitk -from radiomics import base, imageoperations +from radiomics import base, imageoperations, safe_xrange import pdb from tqdm import trange + class RadiomicsGLSZM(base.RadiomicsFeaturesBase): r""" A Gray Level Size Zone (GLSZM) quantifies gray level zones in an image. @@ -87,7 +89,7 @@ def _calculateGLSZM(self): if self.verbose: bar = trange(numGrayLevels - 1, desc='calculate GLSZM') - for i in xrange(1, numGrayLevels): + for i in safe_xrange(1, numGrayLevels): # give some progress if self.verbose: bar.update() diff --git a/radiomics/imageoperations.py b/radiomics/imageoperations.py index 2db38b12..c794e4c4 100644 --- a/radiomics/imageoperations.py +++ b/radiomics/imageoperations.py @@ -274,14 +274,14 @@ def getLoGImage(inputImage, **kwargs): if numpy.min(size) < 4: logger.warning('Image too small to apply LoG filter, size: %s', size) - if kwargs.get('verbose', False): print 'Image too small to apply LoG filter' + if kwargs.get('verbose', False): print('Image too small to apply LoG filter') return sigmaValues = kwargs.get('sigma', numpy.arange(5., 0., -.5)) for sigma in sigmaValues: logger.debug('Computing LoG with sigma %g', sigma) - if kwargs.get('verbose', False): print "\tComputing LoG with sigma %g" % (sigma) + if kwargs.get('verbose', False): print("\tComputing LoG with sigma %g" % (sigma)) if sigma > 0.0: if numpy.all(size >= numpy.ceil(sigma / spacing) + 1): @@ -334,7 +334,7 @@ def getWaveletImage(inputImage, **kwargs): for idx, wl in enumerate(ret, start=1): for decompositionName, decompositionImage in wl.items(): logger.debug('Computing Wavelet %s', decompositionName) - if kwargs.get('verbose', False): print "\tComputing Wavelet %s" % (decompositionName) + if kwargs.get('verbose', False): print("\tComputing Wavelet %s" % (decompositionName)) if idx == 1: inputImageName = 'wavelet-%s' % (decompositionName) diff --git a/tests/testUtils.py b/tests/testUtils.py index be866044..013c6748 100644 --- a/tests/testUtils.py +++ b/tests/testUtils.py @@ -1,3 +1,4 @@ +from __future__ import print_function, unicode_literals, division, absolute_import import SimpleITK as sitk import sys, os import ast @@ -6,7 +7,7 @@ import math import numpy from nose_parameterized import parameterized -from radiomics import imageoperations +from radiomics import imageoperations, in_py3 # Get the logger. This is done outside the class, as it is needed by both the class and the custom_name_func logger = logging.getLogger('testUtils') @@ -155,7 +156,7 @@ def getTestCases(self): """ Return all the test cases for which there are baseline information. """ - return self._baseline[self._baseline.keys()[0]].keys() + return self._baseline[list(self._baseline.keys())[0]].keys() def getFeatureClasses(self): """ @@ -175,9 +176,9 @@ def readBaselineFiles(self): cls = baselineFile[9:-4] self._logger.debug('Reading baseline for class %s', cls) self._baseline[cls] = {} - with open(os.path.join(self._baselineDir, baselineFile), 'rb') as baselineReader: + with open(os.path.join(self._baselineDir, baselineFile), 'r' if in_py3 else 'rb') as baselineReader: csvReader = csv.reader(baselineReader) - headers = csvReader.next() + headers = next(csvReader) for testRow in csvReader: self._baseline[cls][testRow[0]] = {} for val_idx, val in enumerate(testRow[1:], start=1): @@ -244,7 +245,7 @@ def writeCSV(self, data, fileName): csvFile = open(fileName, 'wb') csvFileWriter = csv.writer(csvFile) # get the headers from the first row - header = sorted(data[data.keys()[0]].keys()) + header = sorted(data[list(data.keys())[0]].keys()) header = ['testCase'] + header csvFileWriter.writerow(header) for testCase in sorted(data.keys()): diff --git a/tests/test_docstrings.py b/tests/test_docstrings.py index 25fc2493..60bd82be 100644 --- a/tests/test_docstrings.py +++ b/tests/test_docstrings.py @@ -31,7 +31,7 @@ def teardown_class(self): def generate_scenarios(): global featureClasses - for featureClassName, featureClass in featureClasses.iteritems(): + for featureClassName, featureClass in featureClasses.items(): logging.info('generate_scenarios %s', featureClassName) doc = featureClass.__doc__ assert(doc != None) diff --git a/tests/test_features.py b/tests/test_features.py index deda4ac2..f8678439 100644 --- a/tests/test_features.py +++ b/tests/test_features.py @@ -1,6 +1,7 @@ # to run this test, from directory above: # setenv PYTHONPATH /path/to/pyradiomics/radiomics # nosetests --nocapture -v tests/test_features.py +from __future__ import print_function, unicode_literals, division from radiomics.featureextractor import RadiomicsFeaturesExtractor from testUtils import RadiomicsTestUtils, custom_name_func @@ -52,7 +53,7 @@ def test_scenario(self, testCase, featureClassName, featureName): logging.debug('Init %s' % (featureClassName)) featureClass = extractor.featureClasses[featureClassName](testImage, testMask, **testUtils.getKwargs()) - assert (featureClass != None) + assert featureClass != None featureClass.disableAllFeatures() featureClass.enableFeatureByName(featureName) @@ -65,13 +66,13 @@ def test_scenario(self, testCase, featureClassName, featureName): def teardown_module(): print("") res = testUtils.getResults() - print 'Results:' - print res + print('Results:') + print(res) resultsFile = os.path.join(testUtils.getDataDir(), 'PyradiomicsFeatures.csv') testUtils.writeCSV(res, resultsFile) diff = testUtils.getDiffs() - print 'Differences from baseline:' - print diff + print('Differences from baseline:') + print(diff) diffFile = os.path.join(testUtils.getDataDir(), 'Baseline2PyradiomicsFeaturesDiff.csv') testUtils.writeCSV(diff, diffFile) logging.info( diff --git a/versioneer.py b/versioneer.py index f250cde5..0116069f 100644 --- a/versioneer.py +++ b/versioneer.py @@ -339,9 +339,20 @@ def get_config_from_root(root): # configparser.NoOptionError (if it lacks "VCS="). See the docstring at # the top of versioneer.py for instructions on writing your setup.cfg . setup_cfg = os.path.join(root, "setup.cfg") - parser = configparser.SafeConfigParser() + try: + # python 2 + parser = configparser.SafeConfigParser() + except: + # python 3.2+ + parser = configparser.ConfigParser() + with open(setup_cfg, "r") as f: - parser.readfp(f) + try: + # python 2 + parser.readfp(f) + except: + # python 3.2+ + parser.read_file(f) VCS = parser.get("versioneer", "VCS") # mandatory def get(parser, name): From 5b1e8bb6b2c53a7c9dd371f2dcdf4fc52773908b Mon Sep 17 00:00:00 2001 From: Kevin Mader Date: Thu, 9 Feb 2017 15:16:23 +0100 Subject: [PATCH 2/6] fixing all side classes to be python 3 compatible, updating notebooks, adding a new notebook for simple tests, fixing typo in safe_xrange, most tests pass now, but still differences, probably because SimpleITK, numpy, and PyWavelets have changed. --- bin/Notebooks/PyRadiomics Example.ipynb | 376 +++--- bin/Notebooks/Python3Notebook.ipynb | 461 +++++++ bin/Notebooks/helloFeatureClass.ipynb | 1174 +++++++++-------- bin/Notebooks/helloRadiomics.ipynb | 69 +- bin/batchExamples/DatasetHierarchyReader.py | 2 +- .../GenerateInputCSV_Datasethierarchy.py | 9 +- .../GenerateInputCSV_Filename.py | 19 +- bin/helloFeatureClass.py | 91 +- bin/helloRadiomics.py | 2 +- data/schemaFuncs.py | 9 +- radiomics/__init__.py | 4 +- radiomics/featureextractor.py | 6 +- radiomics/glcm.py | 6 +- radiomics/glrlm.py | 8 +- radiomics/imageoperations.py | 18 +- radiomics/scripts/commandline.py | 2 +- radiomics/shape.py | 17 +- tests/testUtils.py | 10 +- 18 files changed, 1442 insertions(+), 841 deletions(-) create mode 100644 bin/Notebooks/Python3Notebook.ipynb diff --git a/bin/Notebooks/PyRadiomics Example.ipynb b/bin/Notebooks/PyRadiomics Example.ipynb index 1b164bb1..2b76bf1c 100644 --- a/bin/Notebooks/PyRadiomics Example.ipynb +++ b/bin/Notebooks/PyRadiomics Example.ipynb @@ -23,8 +23,8 @@ }, "outputs": [], "source": [ + "from __future__ import print_function, unicode_literals, division, absolute_import\n", "import os # needed navigate the system to get the input data\n", - "\n", "from radiomics import featureextractor # This module is used for interaction with pyradiomics" ] }, @@ -55,9 +55,9 @@ "name": "stdout", "output_type": "stream", "text": [ - "dataDir, relative path: R:\\GitRepos\\pyradiomics\\bin\\Notebooks\\..\\..\\data\n", - "dataDir, absolute path: R:\\GitRepos\\pyradiomics\\data\n", - "Parameter file, absolute path: R:\\GitRepos\\pyradiomics\\bin\\Params.yaml\n" + "dataDir, relative path: /Users/mader/Dropbox/Informatics/pyradiomics/bin/Notebooks/../../data\n", + "dataDir, absolute path: /Users/mader/Dropbox/Informatics/pyradiomics/data\n", + "Parameter file, absolute path: /Users/mader/Dropbox/Informatics/pyradiomics/bin/Params.yaml\n" ] } ], @@ -70,8 +70,8 @@ "# \"..\" points to the parent directory: \\pyradiomics\\bin\\Notebooks\\..\\ is equal to \\pyradiomics\\bin\\\n", "# Move up 2 directories (i.e. go to \\pyradiomics\\) and then move into \\pyradiomics\\data\n", "dataDir = os.path.join(os.getcwd(), \"..\", \"..\", \"data\")\n", - "print \"dataDir, relative path:\", dataDir\n", - "print \"dataDir, absolute path:\", os.path.abspath(dataDir)\n", + "print(\"dataDir, relative path:\", dataDir)\n", + "print(\"dataDir, absolute path:\", os.path.abspath(dataDir))\n", "\n", "# Store the file paths of our testing image and label map into two variables\n", "imagePath = os.path.join(dataDir, testCase + \"_image.nrrd\")\n", @@ -79,7 +79,7 @@ "\n", "# Additonally, store the location of the example parameter file, stored in \\pyradiomics\\bin\n", "paramPath = os.path.join(os.getcwd(), \"..\", \"Params.yaml\")\n", - "print \"Parameter file, absolute path:\", os.path.abspath(paramPath)" + "print(\"Parameter file, absolute path:\", os.path.abspath(paramPath))" ] }, { @@ -122,11 +122,11 @@ "output_type": "stream", "text": [ "Extraction parameters:\n", - "\t{'resampledPixelSpacing': None, 'interpolator': 3, 'verbose': False, 'padDistance': 5, 'label': 1}\n", + "\t {'resampledPixelSpacing': None, 'interpolator': 3, 'label': 1, 'verbose': False, 'padDistance': 5}\n", "Enabled filters:\n", - "\t{'Original': {}}\n", + "\t {'Original': {}}\n", "Enabled features:\n", - "\t{'firstorder': [], 'glcm': [], 'shape': [], 'glrlm': [], 'glszm': []}\n" + "\t {'glcm': [], 'glrlm': [], 'glszm': [], 'shape': [], 'firstorder': []}\n" ] } ], @@ -134,9 +134,9 @@ "# Instantiate the extractor\n", "extractor = featureextractor.RadiomicsFeaturesExtractor()\n", "\n", - "print \"Extraction parameters:\\n\\t\", extractor.kwargs\n", - "print \"Enabled filters:\\n\\t\", extractor.inputImages\n", - "print \"Enabled features:\\n\\t\", extractor.enabledFeatures" + "print(\"Extraction parameters:\\n\\t\", extractor.kwargs)\n", + "print(\"Enabled filters:\\n\\t\", extractor.inputImages)\n", + "print(\"Enabled features:\\n\\t\", extractor.enabledFeatures)" ] }, { @@ -158,11 +158,11 @@ "output_type": "stream", "text": [ "Extraction parameters:\n", - "\t{'verbose': True, 'binWidth': 20, 'label': 1, 'interpolator': 3, 'resampledPixelSpacing': None, 'sigma': [1, 2, 3], 'padDistance': 5}\n", + "\t {'verbose': True, 'sigma': [1, 2, 3], 'binWidth': 20, 'resampledPixelSpacing': None, 'interpolator': 3, 'padDistance': 5, 'label': 1}\n", "Enabled filters:\n", - "\t{'Original': {}}\n", + "\t {'Original': {}}\n", "Enabled features:\n", - "\t{'firstorder': [], 'glcm': [], 'shape': [], 'glrlm': [], 'glszm': []}\n" + "\t {'glcm': [], 'glrlm': [], 'glszm': [], 'shape': [], 'firstorder': []}\n" ] } ], @@ -176,9 +176,9 @@ "# Instantiate the extractor\n", "extractor = featureextractor.RadiomicsFeaturesExtractor(**params) # ** 'unpacks' the dictionary in the function call\n", "\n", - "print \"Extraction parameters:\\n\\t\", extractor.kwargs\n", - "print \"Enabled filters:\\n\\t\", extractor.inputImages # Still the default settings\n", - "print \"Enabled features:\\n\\t\", extractor.enabledFeatures # Still the default settings" + "print(\"Extraction parameters:\\n\\t\", extractor.kwargs)\n", + "print(\"Enabled filters:\\n\\t\", extractor.inputImages) # Still the default settings\n", + "print(\"Enabled features:\\n\\t\", extractor.enabledFeatures) # Still the default settings" ] }, { @@ -193,11 +193,11 @@ "output_type": "stream", "text": [ "Extraction parameters:\n", - "\t{'verbose': True, 'binWidth': 20, 'label': 1, 'interpolator': 3, 'resampledPixelSpacing': None, 'sigma': [1, 2, 3], 'padDistance': 5}\n", + "\t {'verbose': True, 'sigma': [1, 2, 3], 'binWidth': 20, 'resampledPixelSpacing': None, 'interpolator': 3, 'padDistance': 5, 'label': 1}\n", "Enabled filters:\n", - "\t{'Original': {}}\n", + "\t {'Original': {}}\n", "Enabled features:\n", - "\t{'firstorder': [], 'glcm': [], 'shape': [], 'glrlm': [], 'glszm': []}\n" + "\t {'glcm': [], 'glrlm': [], 'glszm': [], 'shape': [], 'firstorder': []}\n" ] } ], @@ -205,9 +205,9 @@ "# This cell is equivalent to the previous cell\n", "extractor = featureextractor.RadiomicsFeaturesExtractor(binWidth=20, sigma=[1, 2, 3], verbose=True) # Equivalent of code above\n", "\n", - "print \"Extraction parameters:\\n\\t\", extractor.kwargs\n", - "print \"Enabled filters:\\n\\t\", extractor.inputImages # Still the default settings\n", - "print \"Enabled features:\\n\\t\", extractor.enabledFeatures # Still the default settings" + "print(\"Extraction parameters:\\n\\t\", extractor.kwargs)\n", + "print(\"Enabled filters:\\n\\t\", extractor.inputImages) # Still the default settings\n", + "print(\"Enabled features:\\n\\t\", extractor.enabledFeatures) # Still the default settings" ] }, { @@ -223,32 +223,32 @@ "text": [ "\n", "Enabled filters:\n", - "\t{'Original': {}, 'LoG': {}}\n", + "\t {'LoG': {}, 'Original': {}}\n", "\n", "Enabled features:\n", - "\t{'firstorder': []}\n", + "\t {'firstorder': []}\n", "\n", "Enabled features:\n", - "\t{'firstorder': [], 'glcm': ['Autocorrelation', 'Homogeneity1', 'SumSquares']}\n" + "\t {'glcm': ['Autocorrelation', 'Homogeneity1', 'SumSquares'], 'firstorder': []}\n" ] } ], "source": [ "# Enable a filter (in addition to the 'Original' filter already enabled)\n", "extractor.enableInputImageByName('LoG')\n", - "print \"\"\n", - "print \"Enabled filters:\\n\\t\", extractor.inputImages\n", + "print(\"\")\n", + "print(\"Enabled filters:\\n\\t\", extractor.inputImages)\n", "\n", "# Disable all feature classes, save firstorder\n", "extractor.disableAllFeatures()\n", "extractor.enableFeatureClassByName('firstorder')\n", - "print \"\"\n", - "print \"Enabled features:\\n\\t\", extractor.enabledFeatures\n", + "print(\"\")\n", + "print(\"Enabled features:\\n\\t\", extractor.enabledFeatures)\n", "\n", "# Specify some additional features in the GLCM feature class\n", "extractor.enableFeaturesByName(glcm=['Autocorrelation', 'Homogeneity1', 'SumSquares'])\n", - "print \"\"\n", - "print \"Enabled features:\\n\\t\", extractor.enabledFeatures" + "print(\"\")\n", + "print(\"Enabled features:\\n\\t\", extractor.enabledFeatures)" ] }, { @@ -270,11 +270,11 @@ "output_type": "stream", "text": [ "Extraction parameters:\n", - "\t{'verbose': True, 'binWidth': 25, 'label': 1, 'interpolator': 'sitkBSpline', 'resampledPixelSpacing': None, 'weightingNorm': None, 'padDistance': 5}\n", + "\t {'verbose': True, 'binWidth': 25, 'resampledPixelSpacing': None, 'weightingNorm': None, 'interpolator': 'sitkBSpline', 'padDistance': 5, 'label': 1}\n", "Enabled filters:\n", - "\t{'Original': {}}\n", + "\t {'Original': {}}\n", "Enabled features:\n", - "\t{'firstorder': [], 'glcm': None, 'shape': None, 'glrlm': None, 'glszm': None}\n" + "\t {'glcm': None, 'glrlm': None, 'glszm': None, 'shape': None, 'firstorder': []}\n" ] } ], @@ -282,9 +282,9 @@ "# Instantiate the extractor\n", "extractor = featureextractor.RadiomicsFeaturesExtractor(paramPath)\n", "\n", - "print \"Extraction parameters:\\n\\t\", extractor.kwargs\n", - "print \"Enabled filters:\\n\\t\", extractor.inputImages\n", - "print \"Enabled features:\\n\\t\", extractor.enabledFeatures" + "print(\"Extraction parameters:\\n\\t\", extractor.kwargs)\n", + "print(\"Enabled filters:\\n\\t\", extractor.inputImages)\n", + "print(\"Enabled features:\\n\\t\", extractor.enabledFeatures)" ] }, { @@ -310,26 +310,75 @@ "collapsed": false }, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "FAILED: Traceback (most recent call last):\n", + " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/base.py\", line 73, in calculateFeatures\n", + " self.featureValues[feature] = eval(call)\n", + " File \"\", line 1, in \n", + " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/shape.py\", line 228, in getMaximum2DDiameterColumnFeatureValue\n", + " return self._getMaximum2Ddiameter(1)\n", + " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/shape.py\", line 126, in _getMaximum2Ddiameter\n", + " for i in numpy.unique(a[:, dim]):\n", + "IndexError: too many indices for array\n", + "\n", + "FAILED: Traceback (most recent call last):\n", + " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/base.py\", line 73, in calculateFeatures\n", + " self.featureValues[feature] = eval(call)\n", + " File \"\", line 1, in \n", + " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/shape.py\", line 221, in getMaximum2DDiameterSliceFeatureValue\n", + " return self._getMaximum2Ddiameter(0)\n", + " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/shape.py\", line 126, in _getMaximum2Ddiameter\n", + " for i in numpy.unique(a[:, dim]):\n", + "IndexError: too many indices for array\n", + "\n", + "FAILED: Traceback (most recent call last):\n", + " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/base.py\", line 73, in calculateFeatures\n", + " self.featureValues[feature] = eval(call)\n", + " File \"\", line 1, in \n", + " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/shape.py\", line 235, in getMaximum2DDiameterRowFeatureValue\n", + " return self._getMaximum2Ddiameter(2)\n", + " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/shape.py\", line 126, in _getMaximum2Ddiameter\n", + " for i in numpy.unique(a[:, dim]):\n", + "IndexError: too many indices for array\n", + "\n", + "calculate GLCM: 24%|██▍ | 8/33 [00:00<00:00, 73.74it/s]" + ] + }, { "name": "stdout", "output_type": "stream", "text": [ - "\t\tComputing shape\n", - "\t\tComputing firstorder\n" + "\t\tComputing shape\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "calculate GLCM: 100%|██████████| 33/33 [00:01<00:00, 32.69it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\t\tComputing glcm\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "calculate GLCM: 100%|██████████████████████████████████████████████████████████████████| 33/33 [00:00<00:00, 38.73it/s]\n" + "calculate GLSZM: 27%|██▋ | 9/33 [00:00<00:00, 89.69it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "\t\tComputing glcm\n", "\t\tComputing glrlm\n" ] }, @@ -337,14 +386,22 @@ "name": "stderr", "output_type": "stream", "text": [ - "calculate GLSZM: 100%|█████████████████████████████████████████████████████████████████| 33/33 [00:00<00:00, 56.90it/s]\n" + "calculate GLSZM: 100%|██████████| 33/33 [00:00<00:00, 72.79it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "\t\tComputing glszm\n" + "\t\tComputing glszm\n", + "\t\tComputing firstorder\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\n" ] } ], @@ -367,139 +424,140 @@ "Result type: \n", "\n", "Calculated features\n", - "\tgeneral_info_BoundingBox : (162; 84; 11; 47; 70; 7)\n", - "\tgeneral_info_GeneralSettings : {'verbose': True; 'binWidth': 25; 'label': 1; 'interpolator': 'sitkBSpline'; 'resampledPixelSpacing': None; 'weightingNorm': None; 'padDistance': 5}\n", - "\tgeneral_info_ImageHash : 5c9ce3ca174f0f8324aa4d277e0fef82dc5ac566\n", - "\tgeneral_info_ImageSpacing : (0.7812499999999999; 0.7812499999999999; 6.499999999999998)\n", - "\tgeneral_info_InputImages : {'Original': {}}\n", - "\tgeneral_info_MaskHash : 9dc2c3137b31fd872997d92c9a92d5178126d9d3\n", - "\tgeneral_info_Version : v1.0.post25.dev0+g00e9e5d\n", - "\tgeneral_info_VolumeNum : 2\n", - "\tgeneral_info_VoxelNum : 4137\n", - "\toriginal_shape_Maximum3DDiameter : 65.5366145873\n", - "\toriginal_shape_Compactness2 : 0.114127701901\n", - "\toriginal_shape_Maximum2DDiameterSlice : 47.2187913633\n", - "\toriginal_shape_Sphericity : 0.485061744222\n", - "\toriginal_shape_Compactness1 : 26.7546787215\n", - "\toriginal_shape_Elongation : 1.7789885567\n", - "\toriginal_shape_SurfaceVolumeRatio : 0.392308261863\n", - "\toriginal_shape_Volume : 16412.6586914\n", - "\toriginal_shape_Flatness : 1.21918505897\n", - "\toriginal_shape_SphericalDisproportion : 2.06159321347\n", - "\toriginal_shape_Roundness : 0.61469066615\n", - "\toriginal_shape_SurfaceArea : 6438.82160378\n", - "\toriginal_shape_Maximum2DDiameterColumn : 44.5487904052\n", - "\toriginal_shape_Maximum2DDiameterRow : 61.5801767135\n", - "\toriginal_firstorder_InterquartileRange : 253.0\n", - "\toriginal_firstorder_Skewness : 0.275650859086\n", - "\toriginal_firstorder_Uniformity : 0.0451569635559\n", - "\toriginal_firstorder_MeanAbsoluteDeviation : 133.447261953\n", - "\toriginal_firstorder_Energy : 33122817481.0\n", - "\toriginal_firstorder_RobustMeanAbsoluteDeviation : 103.00138343\n", - "\toriginal_firstorder_Median : 812.0\n", - "\toriginal_firstorder_TotalEnergy : 131407662126.0\n", - "\toriginal_firstorder_Maximum : 1266.0\n", - "\toriginal_firstorder_RootMeanSquared : 2829.57282108\n", - "\toriginal_firstorder_90Percentile : 1044.4\n", - "\toriginal_firstorder_Minimum : 468.0\n", - "\toriginal_firstorder_Entropy : 4.6019355539\n", - "\toriginal_firstorder_StandardDeviation : 156.611235894\n", - "\toriginal_firstorder_Range : 798.0\n", - "\toriginal_firstorder_Variance : 24527.0792084\n", - "\toriginal_firstorder_10Percentile : 632.0\n", - "\toriginal_firstorder_Kurtosis : 2.18077293939\n", - "\toriginal_firstorder_Mean : 825.235436307\n", - "\toriginal_glcm_SumVariance : 895.891808819\n", - "\toriginal_glcm_Homogeneity1 : 0.276140402104\n", - "\toriginal_glcm_Homogeneity2 : 0.189156155892\n", - "\toriginal_glcm_ClusterShade : -52.9707943386\n", - "\toriginal_glcm_MaximumProbability : 0.00792784235012\n", - "\toriginal_glcm_Idmn : 0.957796447609\n", - "\toriginal_glcm_SumVariance2 : 103.142793792\n", - "\toriginal_glcm_Contrast : 52.2310659277\n", - "\toriginal_glcm_DifferenceEntropy : 3.79686113536\n", - "\toriginal_glcm_InverseVariance : 0.188666637795\n", - "\toriginal_glcm_Entropy : 8.79428086119\n", - "\toriginal_glcm_Dissimilarity : 5.58932678922\n", - "\toriginal_glcm_DifferenceVariance : 17.6107741076\n", - "\toriginal_glcm_Idn : 0.866370546902\n", - "\toriginal_glcm_Idm : 0.189156155892\n", - "\toriginal_glcm_Correlation : 0.335214788202\n", - "\toriginal_glcm_Autocorrelation : 292.684050471\n", - "\toriginal_glcm_SumEntropy : 5.31547876648\n", - "\toriginal_glcm_AverageIntensity : 17.1242601309\n", - "\toriginal_glcm_Energy : 0.00290880217681\n", - "\toriginal_glcm_SumSquares : 39.9781084143\n", - "\toriginal_glcm_ClusterProminence : 26251.1709801\n", - "\toriginal_glcm_SumAverage : 33.4497492152\n", - "\toriginal_glcm_Imc2 : 0.692033706271\n", - "\toriginal_glcm_Imc1 : -0.091940840043\n", - "\toriginal_glcm_DifferenceAverage : 5.58932678922\n", - "\toriginal_glcm_Id : 0.276140402104\n", - "\toriginal_glcm_ClusterTendency : 103.142793792\n", - "\toriginal_glrlm_ShortRunLowGrayLevelEmphasis : 0.00822976624416\n", - "\toriginal_glrlm_GrayLevelVariance : 39.118151022\n", - "\toriginal_glrlm_LowGrayLevelRunEmphasis : 0.00860039789166\n", - "\toriginal_glrlm_GrayLevelNonUniformityNormalized : 0.0451412381498\n", - "\toriginal_glrlm_RunVariance : 0.0847945778959\n", - "\toriginal_glrlm_GrayLevelNonUniformity : 175.635192315\n", - "\toriginal_glrlm_LongRunEmphasis : 1.22684403826\n", - "\toriginal_glrlm_ShortRunHighGrayLevelEmphasis : 268.974179841\n", - "\toriginal_glrlm_RunLengthNonUniformity : 3500.04323157\n", - "\toriginal_glrlm_ShortRunEmphasis : 0.955939173141\n", - "\toriginal_glrlm_LongRunHighGrayLevelEmphasis : 341.286579098\n", - "\toriginal_glrlm_RunPercentage : 0.940406463249\n", - "\toriginal_glrlm_LongRunLowGrayLevelEmphasis : 0.0106011704787\n", - "\toriginal_glrlm_RunEntropy : 4.91503800316\n", - "\toriginal_glrlm_HighGrayLevelRunEmphasis : 281.066493909\n", - "\toriginal_glrlm_RunLengthNonUniformityNormalized : 0.895049465948\n", - "\toriginal_glszm_GrayLevelVariance : 40.6031399239\n", - "\toriginal_glszm_LowIntensityLargeAreaEmphasis : 0.127238415533\n", - "\toriginal_glszm_HighIntensitySmallAreaEmphasis : 193.438051926\n", - "\toriginal_glszm_SmallAreaEmphasis : 0.656447899959\n", - "\toriginal_glszm_LargeAreaEmphasis : 13.6155080214\n", - "\toriginal_glszm_ZoneVariance : 8.72123909749\n", - "\toriginal_glszm_SizeZoneVariabilityNormalized : 0.399784380451\n", - "\toriginal_glszm_LowIntensitySmallAreaEmphasis : 0.0064169820551\n", - "\toriginal_glszm_HighIntensityEmphasis : 288.623529412\n", - "\toriginal_glszm_IntensityVariabilityNormalized : 0.0440573079013\n", - "\toriginal_glszm_ZonePercentage : 0.4520183708\n", - "\toriginal_glszm_LowIntensityEmphasis : 0.00910094202771\n", - "\toriginal_glszm_SizeZoneVariability : 747.596791444\n", - "\toriginal_glszm_IntensityVariability : 82.3871657754\n", - "\toriginal_glszm_ZoneEntropy : 6.5082149862\n", - "\toriginal_glszm_HighIntensityLargeAreaEmphasis : 3514.76149733\n" + "\t general_info_BoundingBox : (162; 84; 11; 47; 70; 7)\n", + "\t general_info_GeneralSettings : {'verbose': True; 'binWidth': 25; 'resampledPixelSpacing': None; 'weightingNorm': None; 'interpolator': 'sitkBSpline'; 'padDistance': 5; 'label': 1}\n", + "\t general_info_ImageHash : 5c9ce3ca174f0f8324aa4d277e0fef82dc5ac566\n", + "\t general_info_ImageSpacing : (0.7812499999999999; 0.7812499999999999; 6.499999999999998)\n", + "\t general_info_InputImages : {'Original': {}}\n", + "\t general_info_MaskHash : 9dc2c3137b31fd872997d92c9a92d5178126d9d3\n", + "\t general_info_Version : v1.0.1.post5.dev0+g72ac3cb\n", + "\t general_info_VolumeNum : 2\n", + "\t general_info_VoxelNum : 4137\n", + "\t original_shape_SurfaceArea : 6438.82160378\n", + "\t original_shape_Sphericity : 0.485061744222\n", + "\t original_shape_Maximum2DDiameterColumn : nan\n", + "\t original_shape_Roundness : 0.6146906661500379\n", + "\t original_shape_Compactness1 : 26.7546787215\n", + "\t original_shape_SurfaceVolumeRatio : 0.392308261863\n", + "\t original_shape_Maximum2DDiameterSlice : nan\n", + "\t original_shape_Maximum3DDiameter : 65.53661458728622\n", + "\t original_shape_Maximum2DDiameterRow : nan\n", + "\t original_shape_Flatness : 1.2191850589688844\n", + "\t original_shape_SphericalDisproportion : 2.06159321347\n", + "\t original_shape_Volume : 16412.65869140624\n", + "\t original_shape_Elongation : 1.7789885567018646\n", + "\t original_shape_Compactness2 : 0.114127701901\n", + "\t original_glcm_Homogeneity2 : 0.189156155892\n", + "\t original_glcm_SumVariance : 895.891808819\n", + "\t original_glcm_DifferenceAverage : 5.58932678922\n", + "\t original_glcm_ClusterProminence : 26251.1709801\n", + "\t original_glcm_DifferenceEntropy : 3.79686113536\n", + "\t original_glcm_Autocorrelation : 292.684050471\n", + "\t original_glcm_SumSquares : 39.9781084143\n", + "\t original_glcm_Dissimilarity : 5.58932678922\n", + "\t original_glcm_SumVariance2 : 103.142793792\n", + "\t original_glcm_ClusterShade : -52.9707943386\n", + "\t original_glcm_ClusterTendency : 103.142793792\n", + "\t original_glcm_Imc2 : 0.692033706271\n", + "\t original_glcm_SumEntropy : 5.31547876648\n", + "\t original_glcm_Imc1 : -0.091940840043\n", + "\t original_glcm_Energy : 0.00290880217681\n", + "\t original_glcm_Correlation : 0.335214788202\n", + "\t original_glcm_Idn : 0.866370546902\n", + "\t original_glcm_Homogeneity1 : 0.276140402104\n", + "\t original_glcm_Entropy : 8.79428086119\n", + "\t original_glcm_DifferenceVariance : 17.6107741076\n", + "\t original_glcm_Idm : 0.189156155892\n", + "\t original_glcm_SumAverage : 33.4497492152\n", + "\t original_glcm_AverageIntensity : 17.1242601309\n", + "\t original_glcm_Id : 0.276140402104\n", + "\t original_glcm_MaximumProbability : 0.00792784235012\n", + "\t original_glcm_InverseVariance : 0.188666637795\n", + "\t original_glcm_Contrast : 52.2310659277\n", + "\t original_glcm_Idmn : 0.957796447609\n", + "\t original_glrlm_LongRunHighGrayLevelEmphasis : 341.908225705\n", + "\t original_glrlm_ShortRunEmphasis : 0.955813827306\n", + "\t original_glrlm_LongRunLowGrayLevelEmphasis : 0.0104694333711\n", + "\t original_glrlm_LowGrayLevelRunEmphasis : 0.00846567390082\n", + "\t original_glrlm_GrayLevelNonUniformityNormalized : 0.0451916226163\n", + "\t original_glrlm_RunVariance : 0.0849939088453\n", + "\t original_glrlm_RunEntropy : 4.91343459806\n", + "\t original_glrlm_RunLengthNonUniformityNormalized : 0.894736783551\n", + "\t original_glrlm_LongRunEmphasis : 1.22741432468\n", + "\t original_glrlm_GrayLevelNonUniformity : 174.640108304\n", + "\t original_glrlm_RunPercentage : 0.934010152284\n", + "\t original_glrlm_GrayLevelVariance : 39.074009627\n", + "\t original_glrlm_HighGrayLevelRunEmphasis : 281.50156957\n", + "\t original_glrlm_RunLengthNonUniformity : 3473.88954354\n", + "\t original_glrlm_ShortRunLowGrayLevelEmphasis : 0.0080944625119\n", + "\t original_glrlm_ShortRunHighGrayLevelEmphasis : 269.366654415\n", + "\t original_glszm_ZoneEntropy : 6.5082149862\n", + "\t original_glszm_HighIntensitySmallAreaEmphasis : 193.438051926\n", + "\t original_glszm_HighIntensityLargeAreaEmphasis : 3514.76149733\n", + "\t original_glszm_LowIntensityEmphasis : 0.00910094202771\n", + "\t original_glszm_IntensityVariability : 82.3871657754\n", + "\t original_glszm_LargeAreaEmphasis : 13.6155080214\n", + "\t original_glszm_GrayLevelVariance : 40.6031399239\n", + "\t original_glszm_ZoneVariance : 8.72123909749\n", + "\t original_glszm_HighIntensityEmphasis : 288.623529412\n", + "\t original_glszm_SizeZoneVariability : 747.596791444\n", + "\t original_glszm_LowIntensitySmallAreaEmphasis : 0.0064169820551\n", + "\t original_glszm_IntensityVariabilityNormalized : 0.0440573079013\n", + "\t original_glszm_ZonePercentage : 0.4520183708\n", + "\t original_glszm_SmallAreaEmphasis : 0.656447899959\n", + "\t original_glszm_LowIntensityLargeAreaEmphasis : 0.127238415533\n", + "\t original_glszm_SizeZoneVariabilityNormalized : 0.399784380451\n", + "\t original_firstorder_Minimum : 468.0\n", + "\t original_firstorder_RobustMeanAbsoluteDeviation : 103.00138343\n", + "\t original_firstorder_Energy : 33122817481.0\n", + "\t original_firstorder_RootMeanSquared : 2829.57282108\n", + "\t original_firstorder_Mean : 825.235436307\n", + "\t original_firstorder_Maximum : 1266.0\n", + "\t original_firstorder_10Percentile : 632.0\n", + "\t original_firstorder_Entropy : 4.6019355539\n", + "\t original_firstorder_TotalEnergy : 131407662126.0\n", + "\t original_firstorder_MeanAbsoluteDeviation : 133.447261953\n", + "\t original_firstorder_Median : 812.0\n", + "\t original_firstorder_Range : 798.0\n", + "\t original_firstorder_StandardDeviation : 156.611235894\n", + "\t original_firstorder_Skewness : 0.275650859086\n", + "\t original_firstorder_Uniformity : 0.0451569635559\n", + "\t original_firstorder_Variance : 24527.0792084\n", + "\t original_firstorder_InterquartileRange : 253.0\n", + "\t original_firstorder_90Percentile : 1044.4\n", + "\t original_firstorder_Kurtosis : 2.18077293939\n" ] } ], "source": [ - "print \"Result type:\", type(result) # result is returned in a Python ordered dictionary\n", - "print \"\"\n", - "print \"Calculated features\"\n", - "for key, value in result.iteritems():\n", - " print \"\\t\", key, \":\", value" + "print(\"Result type:\", type(result)) # result is returned in a Python ordered dictionary\n", + "print(\"\")\n", + "print(\"Calculated features\")\n", + "for key, value in result.items():\n", + " print(\"\\t\", key, \":\", value)" ] } ], "metadata": { + "anaconda-cloud": {}, "kernelspec": { - "display_name": "Python 2", + "display_name": "Python [default]", "language": "python", - "name": "python2" + "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", - "version": 2 + "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.11" + "pygments_lexer": "ipython3", + "version": "3.5.2" } }, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 0 } diff --git a/bin/Notebooks/Python3Notebook.ipynb b/bin/Notebooks/Python3Notebook.ipynb new file mode 100644 index 00000000..958f358e --- /dev/null +++ b/bin/Notebooks/Python3Notebook.ipynb @@ -0,0 +1,461 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "from __future__ import print_function, unicode_literals, division, absolute_import\n", + "import matplotlib.pyplot as plt\n", + "import SimpleITK as sitk\n", + "import numpy as np\n", + "import pandas as pd" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "import radiomics as pyrad\n", + "from radiomics.featureextractor import RadiomicsFeaturesExtractor" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Make Test Image and Mask\n", + "Here we make test images (a simple trianglular mask and a uniform progression)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "test_mask_arr = np.stack(32*[np.eye(32)],0).astype(int)\n", + "test_img_arr = np.linspace(0,100, num = np.prod(test_mask_arr.shape)).reshape(test_mask_arr.shape)\n", + "test_mask = sitk.GetImageFromArray(test_mask_arr)\n", + "test_img = sitk.GetImageFromArray(test_img_arr)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%matplotlib inline\n", + "fig, (ax1, ax2) = plt.subplots(1,2, figsize = (8, 4))\n", + "ax1.imshow(test_mask_arr[0], cmap = 'bone')\n", + "ax2.imshow(test_img_arr[0], cmap = 'RdBu')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Extract simple stats\n", + "Here is just the simple statistics for testing" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\t\tComputing firstorder\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
general_info_BoundingBoxgeneral_info_GeneralSettingsgeneral_info_ImageHashgeneral_info_ImageSpacinggeneral_info_InputImagesgeneral_info_MaskHashgeneral_info_Versiongeneral_info_VolumeNumgeneral_info_VoxelNumoriginal_firstorder_10Percentile...original_firstorder_Medianoriginal_firstorder_Minimumoriginal_firstorder_Rangeoriginal_firstorder_RobustMeanAbsoluteDeviationoriginal_firstorder_RootMeanSquaredoriginal_firstorder_Skewnessoriginal_firstorder_StandardDeviationoriginal_firstorder_TotalEnergyoriginal_firstorder_Uniformityoriginal_firstorder_Variance
0(0; 0; 0; 32; 32; 32){'interpolator': 3; 'verbose': True; 'label': ...dd1063b4904affacbcfa769510e55d35690f6961(1.0; 1.0; 1.0){'Original': {}}d72fb2bdbaffacc0632f4f1a782fdbc10b9155e0v1.0.1.post5.dev0+g72ac3cb1102410.009766...50.00.0100.019.970662050.2032670.028.8692754.304213e+090.25833.435014
\n", + "

1 rows × 28 columns

\n", + "
" + ], + "text/plain": [ + " general_info_BoundingBox general_info_GeneralSettings \\\n", + "0 (0; 0; 0; 32; 32; 32) {'interpolator': 3; 'verbose': True; 'label': ... \n", + "\n", + " general_info_ImageHash general_info_ImageSpacing \\\n", + "0 dd1063b4904affacbcfa769510e55d35690f6961 (1.0; 1.0; 1.0) \n", + "\n", + " general_info_InputImages general_info_MaskHash \\\n", + "0 {'Original': {}} d72fb2bdbaffacc0632f4f1a782fdbc10b9155e0 \n", + "\n", + " general_info_Version general_info_VolumeNum general_info_VoxelNum \\\n", + "0 v1.0.1.post5.dev0+g72ac3cb 1 1024 \n", + "\n", + " original_firstorder_10Percentile ... \\\n", + "0 10.009766 ... \n", + "\n", + " original_firstorder_Median original_firstorder_Minimum \\\n", + "0 50.0 0.0 \n", + "\n", + " original_firstorder_Range original_firstorder_RobustMeanAbsoluteDeviation \\\n", + "0 100.0 19.97066 \n", + "\n", + " original_firstorder_RootMeanSquared original_firstorder_Skewness \\\n", + "0 2050.203267 0.0 \n", + "\n", + " original_firstorder_StandardDeviation original_firstorder_TotalEnergy \\\n", + "0 28.869275 4.304213e+09 \n", + "\n", + " original_firstorder_Uniformity original_firstorder_Variance \n", + "0 0.25 833.435014 \n", + "\n", + "[1 rows x 28 columns]" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "extractor = RadiomicsFeaturesExtractor( verbose = True)\n", + "extractor.disableAllFeatures()\n", + "extractor.enableFeaturesByName(firstorder = [])\n", + "out_dict = extractor.execute(test_img, test_mask)\n", + "pd.DataFrame([out_dict])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Run using everything\n", + "Here we run the extractor with everything, which causes a few issues but returns over 100 columns worth of radiomics features!" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "FAILED: Traceback (most recent call last):\n", + " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/base.py\", line 73, in calculateFeatures\n", + " self.featureValues[feature] = eval(call)\n", + " File \"\", line 1, in \n", + " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/shape.py\", line 221, in getMaximum2DDiameterSliceFeatureValue\n", + " return self._getMaximum2Ddiameter(0)\n", + " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/shape.py\", line 126, in _getMaximum2Ddiameter\n", + " for i in numpy.unique(a[:, dim]):\n", + "IndexError: too many indices for array\n", + "\n", + "FAILED: Traceback (most recent call last):\n", + " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/base.py\", line 73, in calculateFeatures\n", + " self.featureValues[feature] = eval(call)\n", + " File \"\", line 1, in \n", + " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/shape.py\", line 235, in getMaximum2DDiameterRowFeatureValue\n", + " return self._getMaximum2Ddiameter(2)\n", + " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/shape.py\", line 126, in _getMaximum2Ddiameter\n", + " for i in numpy.unique(a[:, dim]):\n", + "IndexError: too many indices for array\n", + "\n", + "FAILED: Traceback (most recent call last):\n", + " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/base.py\", line 73, in calculateFeatures\n", + " self.featureValues[feature] = eval(call)\n", + " File \"\", line 1, in \n", + " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/shape.py\", line 228, in getMaximum2DDiameterColumnFeatureValue\n", + " return self._getMaximum2Ddiameter(1)\n", + " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/shape.py\", line 126, in _getMaximum2Ddiameter\n", + " for i in numpy.unique(a[:, dim]):\n", + "IndexError: too many indices for array\n", + "\n", + "calculate GLCM: 100%|██████████| 4/4 [00:00<00:00, 164.24it/s]\n", + "calculate GLSZM: 0%| | 0/4 [00:00\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
general_info_BoundingBoxgeneral_info_GeneralSettingsgeneral_info_ImageHashgeneral_info_ImageSpacinggeneral_info_InputImagesgeneral_info_MaskHashgeneral_info_Versiongeneral_info_VolumeNumgeneral_info_VoxelNumoriginal_firstorder_10Percentile...original_shape_Maximum2DDiameterColumnoriginal_shape_Maximum2DDiameterRoworiginal_shape_Maximum2DDiameterSliceoriginal_shape_Maximum3DDiameteroriginal_shape_Roundnessoriginal_shape_SphericalDisproportionoriginal_shape_Sphericityoriginal_shape_SurfaceAreaoriginal_shape_SurfaceVolumeRatiooriginal_shape_Volume
0(0; 0; 0; 32; 32; 32){'interpolator': 3; 'verbose': True; 'label': ...dd1063b4904affacbcfa769510e55d35690f6961(1.0; 1.0; 1.0){'Original': {}}d72fb2bdbaffacc0632f4f1a782fdbc10b9155e0v1.0.1.post5.dev0+g72ac3cb1102410.009766...NaNNaNNaN53.6935750.2240415.8237310.1717112861.2253342.7941651024.0
\n", + "

1 rows × 102 columns

\n", + "" + ], + "text/plain": [ + " general_info_BoundingBox general_info_GeneralSettings \\\n", + "0 (0; 0; 0; 32; 32; 32) {'interpolator': 3; 'verbose': True; 'label': ... \n", + "\n", + " general_info_ImageHash general_info_ImageSpacing \\\n", + "0 dd1063b4904affacbcfa769510e55d35690f6961 (1.0; 1.0; 1.0) \n", + "\n", + " general_info_InputImages general_info_MaskHash \\\n", + "0 {'Original': {}} d72fb2bdbaffacc0632f4f1a782fdbc10b9155e0 \n", + "\n", + " general_info_Version general_info_VolumeNum general_info_VoxelNum \\\n", + "0 v1.0.1.post5.dev0+g72ac3cb 1 1024 \n", + "\n", + " original_firstorder_10Percentile ... \\\n", + "0 10.009766 ... \n", + "\n", + " original_shape_Maximum2DDiameterColumn \\\n", + "0 NaN \n", + "\n", + " original_shape_Maximum2DDiameterRow original_shape_Maximum2DDiameterSlice \\\n", + "0 NaN NaN \n", + "\n", + " original_shape_Maximum3DDiameter original_shape_Roundness \\\n", + "0 53.693575 0.224041 \n", + "\n", + " original_shape_SphericalDisproportion original_shape_Sphericity \\\n", + "0 5.823731 0.171711 \n", + "\n", + " original_shape_SurfaceArea original_shape_SurfaceVolumeRatio \\\n", + "0 2861.225334 2.794165 \n", + "\n", + " original_shape_Volume \n", + "0 1024.0 \n", + "\n", + "[1 rows x 102 columns]" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "extractor = RadiomicsFeaturesExtractor(verbose = True)\n", + "extractor.enableAllFeatures()\n", + "out_dict = extractor.execute(test_img, test_mask)\n", + "pd.DataFrame([out_dict])" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Calculating firstorder features\n", + "Calculating shape features\n", + "Calculating glszm features\n", + "Calculating glcm features\n", + "Calculating glrlm features\n" + ] + } + ], + "source": [ + "\n", + "for c_name in extractor.getFeatureClassNames():\n", + " print('Calculating {} features'.format(c_name))\n", + " featureClass = extractor.featureClasses[c_name](test_img, test_mask)" + ] + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python [default]", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.5.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/bin/Notebooks/helloFeatureClass.ipynb b/bin/Notebooks/helloFeatureClass.ipynb index 8477b5be..5e60aa0a 100644 --- a/bin/Notebooks/helloFeatureClass.ipynb +++ b/bin/Notebooks/helloFeatureClass.ipynb @@ -23,6 +23,7 @@ }, "outputs": [], "source": [ + "from __future__ import print_function, unicode_literals, division, absolute_import\n", "import os\n", "import collections\n", "import SimpleITK as sitk\n", @@ -63,9 +64,9 @@ "maskName = os.path.join(dataDir, testCase + '_label.nrrd')\n", "\n", "if not os.path.exists(imageName):\n", - " print 'Error: problem finding input image', imageName\n", + " print('Error: problem finding input image', imageName)\n", "if not os.path.exists(maskName):\n", - " print 'Error: problem finding input labelmap', maskName" + " print('Error: problem finding input labelmap', maskName)" ] }, { @@ -197,10 +198,10 @@ ], "source": [ "# Print out the docstrings of the enabled features\n", - "print 'Will calculate the following first order features: '\n", + "print('Will calculate the following first order features: ')\n", "for f in firstOrderFeatures.enabledFeatures.keys():\n", - " print f\n", - " print eval('firstOrderFeatures.get' + f + 'FeatureValue.__doc__')" + " print(f)\n", + " print(eval('firstOrderFeatures.get' + f + 'FeatureValue.__doc__'))" ] }, { @@ -214,7 +215,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "Calculating first order features... done\n", + "Calculating first order features...\n", + "done\n", "Calculated first order features: \n", " Mean : 825.235436307\n" ] @@ -222,13 +224,13 @@ ], "source": [ "# Calculate the features and print out result\n", - "print 'Calculating first order features...',\n", + "print('Calculating first order features...')\n", "firstOrderFeatures.calculateFeatures()\n", - "print 'done'\n", + "print('done')\n", "\n", - "print 'Calculated first order features: '\n", - "for (key, val) in firstOrderFeatures.featureValues.iteritems():\n", - " print ' ', key, ':', val" + "print('Calculated first order features: ')\n", + "for (key, val) in firstOrderFeatures.featureValues.items():\n", + " print(' ', key, ':', val)" ] }, { @@ -265,21 +267,9 @@ "output_type": "stream", "text": [ "Will calculate the following shape features: \n", - "Maximum3DDiameter\n", - "\n", - " Calculate the largest pairwise euclidean distance between tumor surface voxels.\n", - " Also known as Feret Diameter.\n", - " \n", - "Compactness2\n", + "Elongation\n", "\n", - " Calculate the Compactness (2) of the tumor region.\n", "\n", - " :math:`compactness\\ 2 = 36\\pi\\frac{V^2}{A^3}`\n", - "\n", - " Compactness 2 is a measure of how compact the shape of the tumor is\n", - " relative to a sphere (most compact). It is a dimensionless measure,\n", - " independent of scale and orientation. This is a measure of the compactness\n", - " of the shape of the image ROI.\n", " \n", "Compactness1\n", "\n", @@ -293,84 +283,96 @@ " ratio of volume to the :math:`\\sqrt{\\text{surface area}^3}`. This is a measure of the\n", " compactness of the shape of the image ROI\n", " \n", - "Sphericity\n", + "SurfaceArea\n", "\n", - " Calculate the Sphericity of the tumor region.\n", + " Calculate the surface area of the tumor region in square millimeters.\n", "\n", - " :math:`sphericity = \\frac{\\pi^{\\frac{1}{3}}(6V)^{\\frac{2}{3}}}{A}`\n", + " :math:`A = \\displaystyle\\sum^{N}_{i=1}{\\frac{1}{2}|\\textbf{a}_i\\textbf{b}_i \\times \\textbf{a}_i\\textbf{c}_i|}`\n", + "\n", + " Where:\n", + "\n", + " :math:`N` is the number of triangles forming the surface of the volume\n", + "\n", + " :math:`a_ib_i` and :math:`a_ic_i` are the edges of the :math:`i`\\ :sup:`th` triangle formed by points :math:`a_i`,\n", + " :math:`b_i` and :math:`c_i`\n", "\n", - " Sphericity is a measure of the roundness of the shape of the tumor region\n", - " relative to a sphere. This is another measure of the compactness of a tumor.\n", " \n", "Maximum2DDiameterSlice\n", "\n", " Calculate the largest pairwise euclidean distance between tumor surface voxels in the row-column plane.\n", " \n", - "Elongation\n", + "Compactness2\n", "\n", + " Calculate the Compactness (2) of the tumor region.\n", "\n", + " :math:`compactness\\ 2 = 36\\pi\\frac{V^2}{A^3}`\n", + "\n", + " Compactness 2 is a measure of how compact the shape of the tumor is\n", + " relative to a sphere (most compact). It is a dimensionless measure,\n", + " independent of scale and orientation. This is a measure of the compactness\n", + " of the shape of the image ROI.\n", " \n", - "SurfaceVolumeRatio\n", + "Flatness\n", "\n", - " Calculate the surface area to volume ratio of the tumor region\n", "\n", - " :math:`surface\\ to\\ volume\\ ratio = \\frac{A}{V}`\n", " \n", - "Volume\n", + "Maximum3DDiameter\n", "\n", - " Calculate the volume of the tumor region in cubic millimeters.\n", + " Calculate the largest pairwise euclidean distance between tumor surface voxels.\n", + " Also known as Feret Diameter.\n", " \n", "Roundness\n", "\n", "\n", " \n", - "SphericalDisproportion\n", + "Maximum2DDiameterColumn\n", "\n", - " Calculate the Spherical Disproportion of the tumor region.\n", + " Calculate the largest pairwise euclidean distance between tumor surface voxels in the row-slice plane.\n", + " \n", + "Sphericity\n", "\n", - " :math:`spherical\\ disproportion = \\frac{A}{4\\pi R^2}`\n", + " Calculate the Sphericity of the tumor region.\n", "\n", - " Where :math:`R` is the radius of a sphere with the same volume as the tumor.\n", + " :math:`sphericity = \\frac{\\pi^{\\frac{1}{3}}(6V)^{\\frac{2}{3}}}{A}`\n", "\n", - " Spherical Disproportion is the ratio of the surface area of the\n", - " tumor region to the surface area of a sphere with the same\n", - " volume as the tumor region.\n", + " Sphericity is a measure of the roundness of the shape of the tumor region\n", + " relative to a sphere. This is another measure of the compactness of a tumor.\n", " \n", - "Flatness\n", - "\n", + "Volume\n", "\n", + " Calculate the volume of the tumor region in cubic millimeters.\n", " \n", - "SurfaceArea\n", - "\n", - " Calculate the surface area of the tumor region in square millimeters.\n", + "SurfaceVolumeRatio\n", "\n", - " :math:`A = \\displaystyle\\sum^{N}_{i=1}{\\frac{1}{2}|\\textbf{a}_i\\textbf{b}_i \\times \\textbf{a}_i\\textbf{c}_i|}`\n", + " Calculate the surface area to volume ratio of the tumor region\n", "\n", - " Where:\n", + " :math:`surface\\ to\\ volume\\ ratio = \\frac{A}{V}`\n", + " \n", + "Maximum2DDiameterRow\n", "\n", - " :math:`N` is the number of triangles forming the surface of the volume\n", + " Calculate the largest pairwise euclidean distance between tumor surface voxels in the column-slice plane.\n", + " \n", + "SphericalDisproportion\n", "\n", - " :math:`a_ib_i` and :math:`a_ic_i` are the edges of the :math:`i`\\ :sup:`th` triangle formed by points :math:`a_i`,\n", - " :math:`b_i` and :math:`c_i`\n", + " Calculate the Spherical Disproportion of the tumor region.\n", "\n", - " \n", - "Maximum2DDiameterColumn\n", + " :math:`spherical\\ disproportion = \\frac{A}{4\\pi R^2}`\n", "\n", - " Calculate the largest pairwise euclidean distance between tumor surface voxels in the row-slice plane.\n", - " \n", - "Maximum2DDiameterRow\n", + " Where :math:`R` is the radius of a sphere with the same volume as the tumor.\n", "\n", - " Calculate the largest pairwise euclidean distance between tumor surface voxels in the column-slice plane.\n", + " Spherical Disproportion is the ratio of the surface area of the\n", + " tumor region to the surface area of a sphere with the same\n", + " volume as the tumor region.\n", " \n" ] } ], "source": [ "# Print out the docstrings of the enabled features\n", - "print 'Will calculate the following shape features: '\n", + "print('Will calculate the following shape features: ')\n", "for f in shapeFeatures.enabledFeatures.keys():\n", - " print f\n", - " print eval('shapeFeatures.get' + f + 'FeatureValue.__doc__')" + " print(f)\n", + " print(eval('shapeFeatures.get' + f + 'FeatureValue.__doc__'))" ] }, { @@ -380,38 +382,75 @@ "collapsed": false }, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "FAILED: Traceback (most recent call last):\n", + " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/base.py\", line 73, in calculateFeatures\n", + " self.featureValues[feature] = eval(call)\n", + " File \"\", line 1, in \n", + " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/shape.py\", line 221, in getMaximum2DDiameterSliceFeatureValue\n", + " return self._getMaximum2Ddiameter(0)\n", + " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/shape.py\", line 126, in _getMaximum2Ddiameter\n", + " for i in numpy.unique(a[:, dim]):\n", + "IndexError: too many indices for array\n", + "\n", + "FAILED: Traceback (most recent call last):\n", + " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/base.py\", line 73, in calculateFeatures\n", + " self.featureValues[feature] = eval(call)\n", + " File \"\", line 1, in \n", + " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/shape.py\", line 228, in getMaximum2DDiameterColumnFeatureValue\n", + " return self._getMaximum2Ddiameter(1)\n", + " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/shape.py\", line 126, in _getMaximum2Ddiameter\n", + " for i in numpy.unique(a[:, dim]):\n", + "IndexError: too many indices for array\n", + "\n", + "FAILED: Traceback (most recent call last):\n", + " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/base.py\", line 73, in calculateFeatures\n", + " self.featureValues[feature] = eval(call)\n", + " File \"\", line 1, in \n", + " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/shape.py\", line 235, in getMaximum2DDiameterRowFeatureValue\n", + " return self._getMaximum2Ddiameter(2)\n", + " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/shape.py\", line 126, in _getMaximum2Ddiameter\n", + " for i in numpy.unique(a[:, dim]):\n", + "IndexError: too many indices for array\n", + "\n" + ] + }, { "name": "stdout", "output_type": "stream", "text": [ - "Calculating shape features... done\n", + "Calculating shape features...\n", + "done\n", "Calculated shape features: \n", - " Maximum3DDiameter : 65.5366145873\n", + " Elongation : 1.7789885567018646\n", + " Compactness1 : 26.7546787215\n", + " SurfaceArea : 6438.82160378\n", + " Maximum2DDiameterSlice : nan\n", " Compactness2 : 0.114127701901\n", - " Maximum2DDiameterSlice : 47.2187913633\n", + " Flatness : 1.2191850589688844\n", + " Maximum3DDiameter : 65.53661458728622\n", + " Roundness : 0.6146906661500379\n", + " Maximum2DDiameterColumn : nan\n", " Sphericity : 0.485061744222\n", - " Compactness1 : 26.7546787215\n", - " Elongation : 1.7789885567\n", + " Volume : 16412.65869140624\n", " SurfaceVolumeRatio : 0.392308261863\n", - " Volume : 16412.6586914\n", - " Flatness : 1.21918505897\n", - " SphericalDisproportion : 2.06159321347\n", - " Roundness : 0.61469066615\n", - " SurfaceArea : 6438.82160378\n", - " Maximum2DDiameterColumn : 44.5487904052\n", - " Maximum2DDiameterRow : 61.5801767135\n" + " Maximum2DDiameterRow : nan\n", + " SphericalDisproportion : 2.06159321347\n" ] } ], "source": [ "# Calculate the features and print out result\n", - "print 'Calculating shape features...',\n", + "print('Calculating shape features...')\n", "shapeFeatures.calculateFeatures()\n", - "print 'done'\n", + "print('done')\n", "\n", - "print 'Calculated shape features: '\n", - "for (key, val) in shapeFeatures.featureValues.iteritems():\n", - " print ' ', key, ':', val" + "print('Calculated shape features: ')\n", + "for (key, val) in shapeFeatures.featureValues.items():\n", + " print(' ', key, ':', val)" ] }, { @@ -432,7 +471,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "calculate GLCM: 100%|██████████████████████████████████████████████████████████████████| 33/33 [00:01<00:00, 29.62it/s]\n" + "calculate GLCM: 100%|██████████| 33/33 [00:00<00:00, 44.78it/s]\n" ] } ], @@ -456,114 +495,111 @@ "output_type": "stream", "text": [ "Will calculate the following GLCM features: \n", - "SumVariance\n", + "ClusterTendency\n", "\n", - " Using coefficients pxAddy, kValuesSum, SumEntropy calculate and return the mean Sum Variance.\n", + " Using coefficients :math:`\\mu_x` and :math:`\\mu_y`, calculate and return the mean Cluster Tendency.\n", "\n", - " :math:`sum\\ variance = \\displaystyle\\sum^{2N_g}_{k=2}{(k-SE)^2p_{x+y}(k)}`\n", + " :math:`cluster\\ prominence = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{\\big(i+j-\\mu_x(i)-\\mu_y(j)\\big)^2p(i,j)}`\n", "\n", - " Sum Variance is a measure of heterogeneity that places higher weights on\n", - " neighboring intensity level pairs that deviate more from the mean.\n", + " Cluster Tendency is a measure of groupings of voxels with similar gray-level values.\n", " \n", - "Homogeneity1\n", + "Autocorrelation\n", "\n", - " Using coefficients i, j, calculate and return the mean Homogeneity 1.\n", + " Calculate and return the mean Autocorrelation.\n", "\n", - " :math:`homogeneity\\ 1 = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{\\frac{p(i,j)}{1+|i-j|}}`\n", + " :math:`autocorrelation = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{p(i,j)ij}`\n", "\n", - " Homogeneity 1 is a measure of the similarity in intensity values for\n", - " neighboring voxels. It is a measure of local homogeneity that increases\n", - " with less contrast in the window.\n", + " Autocorrelation is a measure of the magnitude of the\n", + " fineness and coarseness of texture.\n", " \n", - "Homogeneity2\n", + "AverageIntensity\n", "\n", - " Using coefficients i, j, calculate and return the mean Homogeneity 2.\n", + " Return the mean gray level intensity of the :math:`i` distribution.\n", "\n", - " :math:`homogeneity\\ 2 = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{\\frac{p(i,j)}{1+|i-j|^2}}`\n", + " :math:`\\mu_x = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{p(i,j)i}`\n", "\n", - " Homogeneity 2 is a measure of the similarity in intensity values\n", - " for neighboring voxels.\n", + " N.B. As this formula represents the average of the distribution of :math:`i`, it is independent from the\n", + " distribution of :math:`j`. Therefore, only use this formula if the GLCM is symmetrical, where both distrubutions\n", + " are equal.\n", " \n", - "ClusterShade\n", + "SumEntropy\n", "\n", - " Using coefficients i, j, ux, uy, calculate and return the mean Cluster Shade.\n", + " Using coefficient :math:`p_{x+y}`, calculate and return the mean Sum Entropy.\n", "\n", - " :math:`cluster\\ shade = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{\\big(i+j-\\mu_x(i)-\\mu_y(j)\\big)^3p(i,j)}`\n", + " :math:`sum\\ entropy = \\displaystyle\\sum^{2N_g}_{k=2}{p_{x+y}(k)\\log_2\\big(p_{x+y}(k)+\\epsilon\\big)}`\n", "\n", - " Cluster Shade is a measure of the skewness and uniformity of the GLCM.\n", - " A higher cluster shade implies greater asymmetry about the mean.\n", + " Sum Entropy is a sum of neighborhood intensity value differences.\n", " \n", - "MaximumProbability\n", + "Entropy\n", "\n", - " Using P_glcm, calculate and return the mean Maximum Probability.\n", + " Calculate and return the mean Entropy.\n", "\n", - " :math:`maximum\\ probability = \\max\\big(p(i,j)\\big)`\n", + " :math:`entropy = -\\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{p(i,j)\\log_2\\big(p(i,j)+\\epsilon\\big)}`\n", "\n", - " Maximum Probability is occurrences of the most predominant pair of\n", - " neighboring intensity values.\n", + " Entropy is a measure of the randomness/variability in neighborhood intensity values.\n", " \n", - "Idmn\n", + "Energy\n", "\n", - " Using coefficients i, j, Ng, calculate and return the mean Inverse Difference Moment Normalized.\n", + " Calculate and return the mean Energy.\n", "\n", - " :math:`IDMN = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{ \\frac{p(i,j)}{1+\\left(\\frac{|i-j|^2}{N_g^2}\\right)} }`\n", + " :math:`energy = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{\\big(p(i,j)\\big)^2}`\n", "\n", - " IDMN (inverse difference moment normalized) is a measure of the local\n", - " homogeneity of an image. IDMN weights are the inverse of the Contrast\n", - " weights (decreasing exponentially from the diagonal :math:`i=j` in the GLCM).\n", - " Unlike Homogeneity2, IDMN normalizes the square of the difference between\n", - " neighboring intensity values by dividing over the square of the total\n", - " number of discrete intensity values.\n", + " Energy (or Angular Second Moment)is a measure of homogeneous patterns\n", + " in the image. A greater Energy implies that there are more instances\n", + " of intensity value pairs in the image that neighbor each other at\n", + " higher frequencies.\n", " \n", - "SumVariance2\n", + "Homogeneity2\n", "\n", - " Using coefficients pxAddy, kValuesSum, SumAvarage calculate and return the mean Sum Variance.\n", + " Calculate and return the mean Homogeneity 2.\n", "\n", + " :math:`homogeneity\\ 2 = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{\\frac{p(i,j)}{1+|i-j|^2}}`\n", + "\n", + " Homogeneity 2 is a measure of the similarity in intensity values\n", + " for neighboring voxels.\n", + " \n", + "SumVariance2\n", + "\n", + " Using coefficients :math:`p_{x+y}` and SumAvarage (SA) calculate and return the mean Sum Variance 2.\n", " :math:`sum\\ variance\\ 2 = \\displaystyle\\sum^{2N_g}_{k=2}{(k-SA)^2p_{x+y}(k)}`\n", "\n", - " Sum Variance is a measure of heterogeneity that places higher weights on\n", + " Sum Variance 2 is a measure of heterogeneity that places higher weights on\n", " neighboring intensity level pairs that deviate more from the mean.\n", "\n", " This formula differs from SumVariance in that instead of subtracting the SumEntropy from the intensity,\n", " it subtracts the SumAvarage, which is the mean of intensities and not its entropy\n", " \n", - "Contrast\n", + "Homogeneity1\n", "\n", - " Using coefficients i, j, calculate and return the mean Contrast.\n", + " Calculate and return the mean Homogeneity 1.\n", "\n", - " :math:`contrast = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{(i-j)^2p(i,j)}`\n", + " :math:`homogeneity\\ 1 = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{\\frac{p(i,j)}{1+|i-j|}}`\n", "\n", - " Contrast is a measure of the local intensity variation, favoring :math:`P(i,j)`\n", - " values away from the diagonal :math:`(i = j)`. A larger value correlates with\n", - " a greater disparity in intensity values among neighboring voxels.\n", + " Homogeneity 1 is a measure of the similarity in intensity values for\n", + " neighboring voxels. It is a measure of local homogeneity that increases\n", + " with less contrast in the window.\n", " \n", - "DifferenceEntropy\n", - "\n", - " Using coefficients pxSuby, eps, calculate and return the mean Difference Entropy.\n", + "MaximumProbability\n", "\n", - " :math:`difference\\ entropy = \\displaystyle\\sum^{N_g-1}_{k=0}{p_{x-y}(k)\\log_2\\big(p_{x-y}(k)\\big)}`\n", + " Calculate and return the mean Maximum Probability.\n", "\n", - " Difference Entropy is a measure of the randomness/variability\n", - " in neighborhood intensity value differences.\n", - " \n", - "InverseVariance\n", - "Using the i, j coeffients, calculate and return the mean Inverse Variance.\n", + " :math:`maximum\\ probability = \\max\\big(p(i,j)\\big)`\n", "\n", - " :math:`inverse\\ variance = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{\\frac{p(i,j)}{|i-j|^2}}, i \\neq j`\n", + " Maximum Probability is occurrences of the most predominant pair of\n", + " neighboring intensity values.\n", " \n", - "Dissimilarity\n", + "ClusterShade\n", "\n", - " Using coefficients i, j, calculate and return the mean Dissimilarity.\n", + " Using coefficients :math:`\\mu_x` and :math:`\\mu_y`, calculate and return the mean Cluster Shade.\n", "\n", - " :math:`dissimilarity = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{|i-j|p(i,j)}`\n", + " :math:`cluster\\ shade = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{\\big(i+j-\\mu_x(i)-\\mu_y(j)\\big)^3p(i,j)}`\n", "\n", - " Dissimilarity is a measure of local intensity variation. A larger\n", - " value correlates with a greater disparity in intensity values\n", - " among neighboring voxels.\n", + " Cluster Shade is a measure of the skewness and uniformity of the GLCM.\n", + " A higher cluster shade implies greater asymmetry about the mean.\n", " \n", "SumAverage\n", "\n", - " Using coefficients pxAddy, kValuesSum, calculate and return the mean Sum Average.\n", + " Coefficient :math:`p_{x+y}`, calculate and return the mean Sum Average.\n", "\n", " :math:`sum\\ average = \\displaystyle\\sum^{2N_g}_{k=2}{p_{x+y}(k)k}`\n", "\n", @@ -573,7 +609,7 @@ " \n", "DifferenceVariance\n", "\n", - " Using coefficients pxSuby, kValuesDiff, DifferenceAverage calculate and return the mean Difference Variance.\n", + " Using coefficients :math:`p_{x-y}` and DifferenceAverage (DA) calculate and return the mean Difference Variance.\n", "\n", " :math:`Difference\\ variance = \\displaystyle\\sum^{N_g-1}_{k=0}{(1-DA)^2\\textbf{P}_{x-y}(k)}`\n", "\n", @@ -582,7 +618,7 @@ " \n", "Idn\n", "\n", - " Using coefficients i, j, Ng, calculate and return the mean Inverse Difference Normalized.\n", + " Calculate and return the mean Inverse Difference Normalized.\n", "\n", " :math:`IDN = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{ \\frac{p(i,j)}{1+\\left(\\frac{|i-j|}{N_g}\\right)} }`\n", "\n", @@ -591,141 +627,147 @@ " between the neighboring intensity values by dividing over the total number\n", " of discrete intensity values.\n", " \n", - "Idm\n", + "ClusterProminence\n", "\n", - " Using coefficients i, j, calculate and return the mean Inverse Difference Moment.\n", + " Using coefficients :math:`\\mu_x` and :math:`\\mu_y`, calculate and return the mean Cluster Prominence.\n", "\n", - " :math:`IDM = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{ \\frac{\\textbf{P}(i,j)}{1+|i-j|^2} }`\n", + " :math:`cluster\\ prominence = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{\\big( i+j-\\mu_x(i)-\\mu_y(j)\\big)^4p(i,j)}`\n", "\n", - " IDM (inverse difference moment) is a measure of the local\n", - " homogeneity of an image. IDM weights are the inverse of the Contrast\n", - " weights (decreasing exponentially from the diagonal i=j in the GLCM).\n", + " Cluster Prominence is a measure of the skewness and asymmetry of the GLCM.\n", + " A higher values implies more asymmetry about the mean while a lower value\n", + " indicates a peak near the mean value and less variation about the mean.\n", " \n", - "Correlation\n", + "SumSquares\n", "\n", - " Using coefficients i, j, ux, uy, sigx, sigy, calculate and return the mean Correlation.\n", + " Using coefficients :math:`i` and math:`\\mu_x`, calculate and return the mean Sum of Squares (also known as\n", + " Variance) of the :math:`i` distribution.\n", "\n", - " :math:`correlation = \\frac{\\sum^{N_g}_{i=1}\\sum^{N_g}_{j=1}{p(i,j)ij-\\mu_x(i)\\mu_y(j)}}{\\sigma_x(i)\\sigma_y(j)}`\n", + " :math:`sum\\ squares = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{(i-\\mu_x)^2p(i,j)}`\n", "\n", - " Correlation is a value between 0 (uncorrelated) and 1 (perfectly correlated) showing the\n", - " linear dependency of gray level values to their respective voxels in the GLCM.\n", + " Sum of Squares or Variance is a measure in the distribution of neigboring intensity level pairs\n", + " about the mean intensity level in the GLCM.\n", + "\n", + " N.B. This formula represents the variance of the distribution of :math:`i` and is independent from the distribution\n", + " of :math:`j`. Therefore, only use this formula if the GLCM is symmetrical, where VAR(i) is equal to VAR(j).\n", " \n", - "Autocorrelation\n", + "Id\n", "\n", - " Using the i and j arrays, calculate and return the mean Autocorrelation.\n", + " Calculate and return the mean Inverse Difference.\n", "\n", - " :math:`autocorrelation = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{p(i,j)ij}`\n", + " :math:`ID = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{ \\frac{\\textbf{P}(i,j)}{1+|i-j|} }`\n", "\n", - " Autocorrelation is a measure of the magnitude of the\n", - " fineness and coarseness of texture.\n", + " ID (inverse difference) is another measure of the local homogeneity of an image.\n", + " With more uniform gray levels, the denominator will remain low, resulting in a higher overall value.\n", " \n", - "SumEntropy\n", + "Idm\n", "\n", - " Using coefficients pxAddy, eps, calculate and return the mean Sum Entropy.\n", + " Calculate and return the mean Inverse Difference Moment.\n", "\n", - " :math:`sum\\ entropy = \\displaystyle\\sum^{2N_g}_{k=2}{p_{x+y}(k)\\log_2\\big(p_{x+y}(k)+\\epsilon\\big)}`\n", + " :math:`IDM = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{ \\frac{\\textbf{P}(i,j)}{1+|i-j|^2} }`\n", "\n", - " Sum Entropy is a sum of neighborhood intensity value differences.\n", + " IDM (inverse difference moment) is a measure of the local\n", + " homogeneity of an image. IDM weights are the inverse of the Contrast\n", + " weights (decreasing exponentially from the diagonal i=j in the GLCM).\n", " \n", - "AverageIntensity\n", - "\n", - " Return the mean gray level intensity of the :math:`i` distribution.\n", + "InverseVariance\n", "\n", - " :math:`\\mu_x = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{p(i,j)i}`\n", + " Calculate and return the mean Inverse Variance.\n", "\n", - " N.B. As this formula represents the average of the distribution of :math:`i`, it is independent from the\n", - " distribution of :math:`j`. Therefore, only use this formula if the GLCM is symmetrical, where both distrubutions\n", - " are equal.\n", + " :math:`inverse\\ variance = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{\\frac{p(i,j)}{|i-j|^2}}, i \\neq j`\n", " \n", - "Energy\n", + "Dissimilarity\n", "\n", - " Using P_glcm, calculate and return the mean Energy.\n", + " Calculate and return the mean Dissimilarity.\n", "\n", - " :math:`energy = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{\\big(p(i,j)\\big)^2}`\n", + " :math:`dissimilarity = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{|i-j|p(i,j)}`\n", "\n", - " Energy (or Angular Second Moment)is a measure of homogeneous patterns\n", - " in the image. A greater Energy implies that there are more instances\n", - " of intensity value pairs in the image that neighbor each other at\n", - " higher frequencies.\n", + " Dissimilarity is a measure of local intensity variation defined as the mean absolute difference between the\n", + " neighbouring pairs. A larger value correlates with a greater disparity in intensity values\n", + " among neighboring voxels.\n", " \n", - "SumSquares\n", + "Contrast\n", "\n", - " Using coefficients i and ux, calculate and return the mean Sum of Squares (also known as Variance).\n", + " Using the squared difference between gray values of neighbouring paris, calculate and return the mean Contrast.\n", "\n", - " :math:`sum\\ squares = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{(i-\\mu_x)^2p(i,j)}`\n", + " :math:`contrast = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{(i-j)^2p(i,j)}`\n", "\n", - " Sum of Squares or Variance is a measure in the distribution of neigboring intensity level pairs\n", - " about the mean intensity level in the GLCM.\n", + " Contrast is a measure of the local intensity variation, favoring :math:`P(i,j)`\n", + " values away from the diagonal :math:`(i = j)`. A larger value correlates with\n", + " a greater disparity in intensity values among neighboring voxels.\n", + " \n", + "SumVariance\n", "\n", - " N.B. This formula represents the variance of the distribution of :math:`i` and is independent from the distribution\n", - " of :math:`j`. Therefore, only use this formula if the GLCM is symmetrical, where VAR(i) to be equal to VAR(j).\n", + " Using coefficients :math:`p_{x+y}` and SumEntropy (SE) calculate and return the mean Sum Variance.\n", + "\n", + " :math:`sum\\ variance = \\displaystyle\\sum^{2N_g}_{k=2}{(k-SE)^2p_{x+y}(k)}`\n", + "\n", + " Sum Variance is a measure of heterogeneity that places higher weights on\n", + " neighboring intensity level pairs that deviate more from the mean.\n", " \n", - "ClusterProminence\n", + "DifferenceEntropy\n", "\n", - " Using coefficients i, j, ux, uy, calculate and return the mean Cluster Prominence.\n", + " Using coefficient :math:`p_{x-y}`, calculate and return the mean Difference Entropy.\n", "\n", - " :math:`cluster\\ prominence = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{\\big( i+j-\\mu_x(i)-\\mu_y(j)\\big)^4p(i,j)}`\n", + " :math:`difference\\ entropy = \\displaystyle\\sum^{N_g-1}_{k=0}{p_{x-y}(k)\\log_2\\big(p_{x-y}(k)+\\epsilon\\big)}`\n", "\n", - " Cluster Prominence is a measure of the skewness and asymmetry of the GLCM.\n", - " A higher values implies more asymmetry about the mean while a lower value\n", - " indicates a peak near the mean value and less variation about the mean.\n", + " Difference Entropy is a measure of the randomness/variability\n", + " in neighborhood intensity value differences.\n", " \n", - "Entropy\n", + "Idmn\n", "\n", - " Using coefficients eps, calculate and return the mean Entropy.\n", + " Calculate and return the mean Inverse Difference Moment Normalized.\n", "\n", - " :math:`entropy = -\\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{p(i,j)\\log_2\\big(p(i,j)+\\epsilon\\big)}`\n", + " :math:`IDMN = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{ \\frac{p(i,j)}{1+\\left(\\frac{|i-j|^2}{N_g^2}\\right)} }`\n", "\n", - " Entropy is a measure of the randomness/variability in neighborhood intensity values.\n", + " IDMN (inverse difference moment normalized) is a measure of the local\n", + " homogeneity of an image. IDMN weights are the inverse of the Contrast\n", + " weights (decreasing exponentially from the diagonal :math:`i=j` in the GLCM).\n", + " Unlike Homogeneity2, IDMN normalizes the square of the difference between\n", + " neighboring intensity values by dividing over the square of the total\n", + " number of discrete intensity values.\n", " \n", - "Imc2\n", + "Correlation\n", "\n", - " Using coefficients HXY, HXY2, calculate and return the mean Informal Measure of Correlation 2.\n", + " Using coefficients :math:`\\mu_x`, :math:`\\mu_y`, :math:`\\sigma_x` and :math:`\\sigma_y`, calculate and return the\n", + " mean Correlation.\n", "\n", - " :math:`IMC\\ 2 = \\sqrt{1-e^{-2(HXY2-HXY)}}`\n", + " :math:`correlation = \\frac{\\sum^{N_g}_{i=1}\\sum^{N_g}_{j=1}{p(i,j)ij-\\mu_x(i)\\mu_y(j)}}{\\sigma_x(i)\\sigma_y(j)}`\n", + "\n", + " Correlation is a value between 0 (uncorrelated) and 1 (perfectly correlated) showing the\n", + " linear dependency of gray level values to their respective voxels in the GLCM.\n", " \n", "Imc1\n", "\n", - " Using coefficients HX, HY, HXY, HXY1, calculate and return the mean Informal Measure of Correlation 1.\n", + " Using coefficients :math:`HX`, :math:`HY`, :math:`HXY` and :math:`HXY1`, calculate and return the mean Informal\n", + " Measure of Correlation 1.\n", "\n", " :math:`IMC\\ 1 = \\frac{HXY-HXY1}{\\max\\{HX,HY\\}}`\n", " \n", + "Imc2\n", + "\n", + " Using coefficients :math:`HXY` and :math:`HXY2`, calculate and return the mean Informal Measure of Correlation 2.\n", + "\n", + " :math:`IMC\\ 2 = \\sqrt{1-e^{-2(HXY2-HXY)}}`\n", + " \n", "DifferenceAverage\n", "\n", - " Using coefficients pxMiny, kValuesDiff, calculate and return the mean Difference Average.\n", + " Using coefficient :math:`p_{x-y}`, calculate and return the mean Difference Average.\n", "\n", " :math:`Difference\\ average = \\displaystyle\\sum^{N_g-1}_{k=0}{k\\textbf{P}_{x-y}(k)}`\n", "\n", " Difference Average measures the relationship between occurrences of pairs\n", " with similar intensity values and occurrences of pairs with differing intensity\n", " values.\n", - " \n", - "Id\n", - "\n", - " Using coefficients i, j, Ng, calculate and return the mean Inverse Difference.\n", - "\n", - " :math:`ID = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{ \\frac{\\textbf{P}(i,j)}{1+|i-j|} }`\n", - "\n", - " ID (inverse difference) is another measure of the local homogeneity of an image.\n", - " With more uniform gray levels, the denominator will remain low, resulting in a higher overall value.\n", - " \n", - "ClusterTendency\n", - "\n", - " Using coefficients i, j, ux, uy, calculate and return the mean Cluster Tendency.\n", - "\n", - " :math:`cluster\\ prominence = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{\\big(i+j-\\mu_x(i)-\\mu_y(j)\\big)^2p(i,j)}`\n", - "\n", - " Cluster Tendency is a measure of groupings of voxels with similar gray-level values.\n", " \n" ] } ], "source": [ "# Print out the docstrings of the enabled features\n", - "print 'Will calculate the following GLCM features: '\n", + "print('Will calculate the following GLCM features: ')\n", "for f in glcmFeatures.enabledFeatures.keys():\n", - " print f\n", - " print eval('glcmFeatures.get' + f + 'FeatureValue.__doc__')" + " print(f)\n", + " print(eval('glcmFeatures.get' + f + 'FeatureValue.__doc__'))" ] }, { @@ -739,48 +781,49 @@ "name": "stdout", "output_type": "stream", "text": [ - "Calculating GLCM features... done\n", + "Calculating GLCM features...\n", + "done\n", "Calculated GLCM features: \n", - " SumVariance : 895.891808819\n", - " Homogeneity1 : 0.276140402104\n", - " Homogeneity2 : 0.189156155892\n", - " ClusterShade : -52.9707943386\n", - " MaximumProbability : 0.00792784235012\n", - " Idmn : 0.957796447609\n", - " SumVariance2 : 103.142793792\n", - " Contrast : 52.2310659277\n", - " DifferenceEntropy : 3.79686113536\n", - " InverseVariance : 0.188666637795\n", - " Entropy : 8.79428086119\n", - " Dissimilarity : 5.58932678922\n", - " DifferenceVariance : 17.6107741076\n", - " Idn : 0.866370546902\n", - " Idm : 0.189156155892\n", - " Correlation : 0.335214788202\n", + " ClusterTendency : 103.142793792\n", " Autocorrelation : 292.684050471\n", - " SumEntropy : 5.31547876648\n", " AverageIntensity : 17.1242601309\n", + " SumEntropy : 5.31547876648\n", + " DifferenceAverage : 5.58932678922\n", + " Entropy : 8.79428086119\n", " Energy : 0.00290880217681\n", - " SumSquares : 39.9781084143\n", - " ClusterProminence : 26251.1709801\n", + " Homogeneity2 : 0.189156155892\n", + " SumVariance2 : 103.142793792\n", + " Homogeneity1 : 0.276140402104\n", + " MaximumProbability : 0.00792784235012\n", + " ClusterShade : -52.9707943386\n", " SumAverage : 33.4497492152\n", - " Imc2 : 0.692033706271\n", - " Imc1 : -0.091940840043\n", - " DifferenceAverage : 5.58932678922\n", + " DifferenceVariance : 17.6107741076\n", + " Idn : 0.866370546902\n", + " ClusterProminence : 26251.1709801\n", + " SumSquares : 39.9781084143\n", " Id : 0.276140402104\n", - " ClusterTendency : 103.142793792\n" + " Idm : 0.189156155892\n", + " InverseVariance : 0.188666637795\n", + " Dissimilarity : 5.58932678922\n", + " Contrast : 52.2310659277\n", + " SumVariance : 895.891808819\n", + " DifferenceEntropy : 3.79686113536\n", + " Imc2 : 0.692033706271\n", + " Correlation : 0.335214788202\n", + " Idmn : 0.957796447609\n", + " Imc1 : -0.091940840043\n" ] } ], "source": [ "# Calculate the features and print out result\n", - "print 'Calculating GLCM features...',\n", + "print('Calculating GLCM features...')\n", "glcmFeatures.calculateFeatures()\n", - "print 'done'\n", + "print('done')\n", "\n", - "print 'Calculated GLCM features: '\n", - "for (key, val) in glcmFeatures.featureValues.iteritems():\n", - " print ' ', key, ':', val" + "print('Calculated GLCM features: ')\n", + "for (key, val) in glcmFeatures.featureValues.items():\n", + " print(' ', key, ':', val)" ] }, { @@ -817,23 +860,23 @@ "output_type": "stream", "text": [ "Will calculate the following GLRLM features: \n", - "ShortRunLowGrayLevelEmphasis\n", + "RunLengthNonUniformity\n", "\n", - " Calculate and return the mean Short Run Low Gray Level Emphasis (SRLGLE) value for all GLRLMs.\n", + " Calculate and return the mean Run Length Non-Uniformity (RLN) value for all GLRLMs.\n", "\n", - " :math:`SRLGLE = \\frac{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\frac{\\textbf{P}(i,j|\\theta)}{i^2j^2}}}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}}`\n", + " :math:`RLN = \\frac{\\sum^{N_r}_{j=1}\\left(\\sum^{N_g}_{i=1}{\\textbf{P}(i,j|\\theta)}\\right)^2}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}}`\n", "\n", - " Measures the joint distribution of shorter run lengths with lower gray-level values.\n", + " Measures the similarity of run lengths throughout the image, with a lower value indicating\n", + " more homogeneity among run lengths in the image.\n", " \n", - "GrayLevelVariance\n", - "\n", - " Calculate and return the Gray Level Variance (GLV) value.\n", + "LongRunEmphasis\n", "\n", - " :math:`GLV = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_r}_{j=1}{p(i,j|\\theta)(i - \\mu)^2}`, where\n", + " Calculate and return the mean Long Run Emphasis (LRE) value for all GLRLMs.\n", "\n", - " :math:`\\mu = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_r}_{j=1}{p(i,j|\\theta)i}`\n", + " :math:`LRE = \\frac{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)j^2}}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}}`\n", "\n", - " Measures the variance in gray level intensity for the runs.\n", + " A measure of the distribution of long run lengths, with a greater value indicative\n", + " of longer run lengths and more coarse structural textures.\n", " \n", "LowGrayLevelRunEmphasis\n", "\n", @@ -844,15 +887,6 @@ " Measures the distribution of low gray-level values, with a higher value indicating a greater\n", " concentration of low gray-level values in the image.\n", " \n", - "GrayLevelNonUniformityNormalized\n", - "\n", - " Calculate and return the Gray Level Non-Uniformity Normalized (GLNN) value.\n", - "\n", - " :math:`GLNN = \\frac{\\sum^{N_g}_{i=1}\\left(\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}\\right)^2}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}^2}`\n", - "\n", - " Measures the similarity of gray-level intensity values in the image, where a lower GLNN value\n", - " correlates with a greater similarity in intensity values. This is the normalized version of the GLN formula.\n", - " \n", "RunVariance\n", "\n", " Calculate and return the Run Variance (RV) value.\n", @@ -863,6 +897,32 @@ "\n", " Measures the variance in runs for the run lengths.\n", " \n", + "GrayLevelVariance\n", + "\n", + " Calculate and return the Gray Level Variance (GLV) value.\n", + "\n", + " :math:`GLV = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_r}_{j=1}{p(i,j|\\theta)(i - \\mu)^2}`, where\n", + "\n", + " :math:`\\mu = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_r}_{j=1}{p(i,j|\\theta)i}`\n", + "\n", + " Measures the variance in gray level intensity for the runs.\n", + " \n", + "RunPercentage\n", + "\n", + " Calculate and return the mean Run Percentage (RP) value for all GLRLMs.\n", + "\n", + " :math:`RP = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_r}_{j=1}{\\frac{\\textbf{P}(i,j|\\theta)}{N_p}}`\n", + "\n", + " Measures the homogeneity and distribution of runs of an image.\n", + " \n", + "LongRunLowGrayLevelEmphasis\n", + "\n", + " Calculate and return the mean Long Run Low Gray Level Emphasis (LRLGLE) value for all GLRLMs.\n", + "\n", + " :math:`LRLGLRE = \\frac{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\frac{\\textbf{P}(i,j|\\theta)j^2}{i^2}}}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}}`\n", + "\n", + " Measures the joint distribution of long run lengths with lower gray-level values.\n", + " \n", "GrayLevelNonUniformity\n", "\n", " Calculate and return the mean Gray Level Non-Uniformity (GLN) value for all GLRLMs.\n", @@ -872,31 +932,31 @@ " Measures the similarity of gray-level intensity values in the image, where a lower GLN value\n", " correlates with a greater similarity in intensity values.\n", " \n", - "LongRunEmphasis\n", + "RunLengthNonUniformityNormalized\n", "\n", - " Calculate and return the mean Long Run Emphasis (LRE) value for all GLRLMs.\n", + " Calculate and return the mean Run Length Non-Uniformity Normalized (RLNN) value for all GLRLMs.\n", "\n", - " :math:`LRE = \\frac{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)j^2}}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}}`\n", + " :math:`RLNN = \\frac{\\sum^{N_r}_{j=1}\\left(\\sum^{N_g}_{i=1}{\\textbf{P}(i,j|\\theta)}\\right)^2}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}}`\n", "\n", - " A measure of the distribution of long run lengths, with a greater value indicative\n", - " of longer run lengths and more coarse structural textures.\n", + " Measures the similarity of run lengths throughout the image, with a lower value indicating\n", + " more homogeneity among run lengths in the image. This is the normalized version of the RLN formula.\n", " \n", - "ShortRunHighGrayLevelEmphasis\n", + "HighGrayLevelRunEmphasis\n", "\n", - " Calculate and return the mean Short Run High Gray Level Emphasis (SRHGLE) value for all GLRLMs.\n", + " Calculate and return the mean High Gray Level Run Emphasis (HGLRE) value for all GLRLMs.\n", "\n", - " :math:`SRHGLE = \\frac{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\frac{\\textbf{P}(i,j|\\theta)i^2}{j^2}}}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}}`\n", + " :math:`HGLRE = \\frac{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)i^2}}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}}`\n", "\n", - " Measures the joint distribution of shorter run lengths with higher gray-level values.\n", + " Measures the distribution of the higher gray-level values, with a higher value indicating\n", + " a greater concentration of high gray-level values in the image.\n", " \n", - "RunLengthNonUniformity\n", + "LongRunHighGrayLevelEmphasis\n", "\n", - " Calculate and return the mean Run Length Non-Uniformity (RLN) value for all GLRLMs.\n", + " Calculate and return the mean Long Run High Gray Level Emphasis (LRHGLE) value for all GLRLMs.\n", "\n", - " :math:`RLN = \\frac{\\sum^{N_r}_{j=1}\\left(\\sum^{N_g}_{i=1}{\\textbf{P}(i,j|\\theta)}\\right)^2}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}}`\n", + " :math:`LRHGLRE = \\frac{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)i^2j^2}}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}}`\n", "\n", - " Measures the similarity of run lengths throughout the image, with a lower value indicating\n", - " more homogeneity among run lengths in the image.\n", + " Measures the joint distribution of long run lengths with higher gray-level values.\n", " \n", "ShortRunEmphasis\n", "\n", @@ -907,63 +967,48 @@ " A measure of the distribution of short run lengths, with a greater value indicative\n", " of shorter run lengths and more fine textural textures.\n", " \n", - "LongRunHighGrayLevelEmphasis\n", + "GrayLevelNonUniformityNormalized\n", "\n", - " Calculate and return the mean Long Run High Gray Level Emphasis (LRHGLE) value for all GLRLMs.\n", + " Calculate and return the Gray Level Non-Uniformity Normalized (GLNN) value.\n", "\n", - " :math:`LRHGLRE = \\frac{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)i^2j^2}}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}}`\n", + " :math:`GLNN = \\frac{\\sum^{N_g}_{i=1}\\left(\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}\\right)^2}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}^2}`\n", "\n", - " Measures the joint distribution of long run lengths with higher gray-level values.\n", + " Measures the similarity of gray-level intensity values in the image, where a lower GLNN value\n", + " correlates with a greater similarity in intensity values. This is the normalized version of the GLN formula.\n", " \n", - "RunPercentage\n", + "ShortRunHighGrayLevelEmphasis\n", "\n", - " Calculate and return the mean Run Percentage (RP) value for all GLRLMs.\n", + " Calculate and return the mean Short Run High Gray Level Emphasis (SRHGLE) value for all GLRLMs.\n", "\n", - " :math:`RP = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_r}_{j=1}{\\frac{\\textbf{P}(i,j|\\theta)}{N_p}}`\n", + " :math:`SRHGLE = \\frac{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\frac{\\textbf{P}(i,j|\\theta)i^2}{j^2}}}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}}`\n", "\n", - " Measures the homogeneity and distribution of runs of an image.\n", + " Measures the joint distribution of shorter run lengths with higher gray-level values.\n", " \n", - "LongRunLowGrayLevelEmphasis\n", + "ShortRunLowGrayLevelEmphasis\n", "\n", - " Calculate and return the mean Long Run Low Gray Level Emphasis (LRLGLE) value for all GLRLMs.\n", + " Calculate and return the mean Short Run Low Gray Level Emphasis (SRLGLE) value for all GLRLMs.\n", "\n", - " :math:`LRLGLRE = \\frac{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\frac{\\textbf{P}(i,j|\\theta)j^2}{i^2}}}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}}`\n", + " :math:`SRLGLE = \\frac{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\frac{\\textbf{P}(i,j|\\theta)}{i^2j^2}}}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}}`\n", "\n", - " Measures the joint distribution of long run lengths with lower gray-level values.\n", + " Measures the joint distribution of shorter run lengths with lower gray-level values.\n", " \n", "RunEntropy\n", - "1\n", + "\n", " Calculate and return the Run Entropy (RE) value.\n", "\n", " :math:`RE = -\\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_r}_{j=1}{p(i,j|\\theta)\\log_{2}(p(i,j|\\theta)+\\epsilon)}`\n", - " \n", - "HighGrayLevelRunEmphasis\n", - "\n", - " Calculate and return the mean High Gray Level Run Emphasis (HGLRE) value for all GLRLMs.\n", "\n", - " :math:`HGLRE = \\frac{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)i^2}}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}}`\n", - "\n", - " Measures the distribution of the higher gray-level values, with a higher value indicating\n", - " a greater concentration of high gray-level values in the image.\n", - " \n", - "RunLengthNonUniformityNormalized\n", - "\n", - " Calculate and return the mean Run Length Non-Uniformity Normalized (RLNN) value for all GLRLMs.\n", - "\n", - " :math:`RLNN = \\frac{\\sum^{N_r}_{j=1}\\left(\\sum^{N_g}_{i=1}{\\textbf{P}(i,j|\\theta)}\\right)^2}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}}`\n", - "\n", - " Measures the similarity of run lengths throughout the image, with a lower value indicating\n", - " more homogeneity among run lengths in the image. This is the normalized version of the RLN formula.\n", + " Here, :math:`\\epsilon` is an arbitrarily small positive number (:math:`\\approx 2.2\\times10^{-16}`).\n", " \n" ] } ], "source": [ "# Print out the docstrings of the enabled features\n", - "print 'Will calculate the following GLRLM features: '\n", + "print('Will calculate the following GLRLM features: ')\n", "for f in glrlmFeatures.enabledFeatures.keys():\n", - " print f\n", - " print eval('glrlmFeatures.get' + f + 'FeatureValue.__doc__')" + " print(f)\n", + " print(eval('glrlmFeatures.get' + f + 'FeatureValue.__doc__'))" ] }, { @@ -977,36 +1022,37 @@ "name": "stdout", "output_type": "stream", "text": [ - "Calculating GLRLM features... done\n", + "Calculating GLRLM features...\n", + "done\n", "Calculated GLRLM features: \n", - " ShortRunLowGrayLevelEmphasis : 0.00822976624416\n", - " GrayLevelVariance : 39.118151022\n", - " LowGrayLevelRunEmphasis : 0.00860039789166\n", - " GrayLevelNonUniformityNormalized : 0.0451412381498\n", - " RunVariance : 0.0847945778959\n", - " GrayLevelNonUniformity : 175.635192315\n", - " LongRunEmphasis : 1.22684403826\n", - " ShortRunHighGrayLevelEmphasis : 268.974179841\n", - " RunLengthNonUniformity : 3500.04323157\n", - " ShortRunEmphasis : 0.955939173141\n", - " LongRunHighGrayLevelEmphasis : 341.286579098\n", - " RunPercentage : 0.940406463249\n", - " LongRunLowGrayLevelEmphasis : 0.0106011704787\n", - " RunEntropy : 4.91503800316\n", - " HighGrayLevelRunEmphasis : 281.066493909\n", - " RunLengthNonUniformityNormalized : 0.895049465948\n" + " RunLengthNonUniformity : 3473.88954354\n", + " LongRunEmphasis : 1.22741432468\n", + " LowGrayLevelRunEmphasis : 0.00846567390082\n", + " RunVariance : 0.0849939088453\n", + " GrayLevelVariance : 39.074009627\n", + " RunPercentage : 0.934010152284\n", + " LongRunLowGrayLevelEmphasis : 0.0104694333711\n", + " GrayLevelNonUniformity : 174.640108304\n", + " RunLengthNonUniformityNormalized : 0.894736783551\n", + " HighGrayLevelRunEmphasis : 281.50156957\n", + " LongRunHighGrayLevelEmphasis : 341.908225705\n", + " ShortRunEmphasis : 0.955813827306\n", + " GrayLevelNonUniformityNormalized : 0.0451916226163\n", + " ShortRunHighGrayLevelEmphasis : 269.366654415\n", + " ShortRunLowGrayLevelEmphasis : 0.0080944625119\n", + " RunEntropy : 4.91343459806\n" ] } ], "source": [ "# Calculate the features and print out result\n", - "print 'Calculating GLRLM features...',\n", + "print('Calculating GLRLM features...')\n", "glrlmFeatures.calculateFeatures()\n", - "print 'done'\n", + "print('done')\n", "\n", - "print 'Calculated GLRLM features: '\n", - "for (key, val) in glrlmFeatures.featureValues.iteritems():\n", - " print ' ', key, ':', val" + "print('Calculated GLRLM features: ')\n", + "for (key, val) in glrlmFeatures.featureValues.items():\n", + " print(' ', key, ':', val)" ] }, { @@ -1032,7 +1078,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 20, "metadata": { "collapsed": false }, @@ -1050,7 +1096,7 @@ "source": [ "logFeatures = {}\n", "sigmaValues = [1.0, 3.0, 5.0]\n", - "for logImage, inputImageName, inputKwargs in imageoperations.applyFilterLoG(image, sigma=sigmaValues, verbose=True):\n", + "for logImage, inputImageName, inputKwargs in imageoperations.getLoGImage(image, sigma=sigmaValues, verbose=True):\n", " logImage, croppedMask, bb = imageoperations.cropToTumorMask(logImage, mask)\n", " logFirstorderFeatures = firstorder.RadiomicsFirstOrder(logImage, croppedMask, **inputKwargs)\n", " logFirstorderFeatures.enableAllFeatures()\n", @@ -1060,7 +1106,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 21, "metadata": { "collapsed": false }, @@ -1069,72 +1115,72 @@ "name": "stdout", "output_type": "stream", "text": [ - " log-sigma-3-0-mm-3D_InterquartileRange : 103.158138275\n", - " log-sigma-3-0-mm-3D_Skewness : -0.498386343995\n", - " log-sigma-3-0-mm-3D_Uniformity : 0.0906478492348\n", - " log-sigma-3-0-mm-3D_MeanAbsoluteDeviation : 64.3312024633\n", - " log-sigma-3-0-mm-3D_Energy : 15235011555.6\n", - " log-sigma-3-0-mm-3D_RobustMeanAbsoluteDeviation : 43.3779243984\n", - " log-sigma-3-0-mm-3D_Median : -73.3129653931\n", - " log-sigma-3-0-mm-3D_TotalEnergy : 60441635199.8\n", - " log-sigma-3-0-mm-3D_Maximum : 114.296691895\n", - " log-sigma-3-0-mm-3D_RootMeanSquared : 1919.01616706\n", - " log-sigma-3-0-mm-3D_90Percentile : 13.9173410416\n", - " log-sigma-3-0-mm-3D_Minimum : -354.335235596\n", - " log-sigma-3-0-mm-3D_Entropy : 3.72121444058\n", - " log-sigma-3-0-mm-3D_StandardDeviation : 81.9760118492\n", - " log-sigma-3-0-mm-3D_Range : 468.63192749\n", - " log-sigma-3-0-mm-3D_Variance : 6720.06651871\n", - " log-sigma-3-0-mm-3D_10Percentile : -197.017340088\n", - " log-sigma-3-0-mm-3D_Kurtosis : 3.18336583197\n", - " log-sigma-3-0-mm-3D_Mean : -82.7355469484\n", - " log-sigma-1-0-mm-3D_InterquartileRange : 81.8767185211\n", - " log-sigma-1-0-mm-3D_Skewness : -0.220905251704\n", - " log-sigma-1-0-mm-3D_Uniformity : 0.114235313372\n", - " log-sigma-1-0-mm-3D_MeanAbsoluteDeviation : 49.6646616511\n", + " log-sigma-5-0-mm-3D_RootMeanSquared : 1896.44460614\n", + " log-sigma-5-0-mm-3D_Energy : 14878729370.4\n", + " log-sigma-5-0-mm-3D_Uniformity : 0.0902675928609\n", + " log-sigma-5-0-mm-3D_Maximum : 117.414512634\n", + " log-sigma-5-0-mm-3D_Range : 464.759513855\n", + " log-sigma-5-0-mm-3D_Skewness : -0.30549686903\n", + " log-sigma-5-0-mm-3D_Kurtosis : 3.11489160873\n", + " log-sigma-5-0-mm-3D_Median : -99.1174468994\n", + " log-sigma-5-0-mm-3D_Variance : 6483.79391901\n", + " log-sigma-5-0-mm-3D_10Percentile : -211.974316406\n", + " log-sigma-5-0-mm-3D_Entropy : 3.71336391413\n", + " log-sigma-5-0-mm-3D_TotalEnergy : 59028162175.1\n", + " log-sigma-5-0-mm-3D_InterquartileRange : 106.342716217\n", + " log-sigma-5-0-mm-3D_MeanAbsoluteDeviation : 63.4364264458\n", + " log-sigma-5-0-mm-3D_StandardDeviation : 80.5220089107\n", + " log-sigma-5-0-mm-3D_90Percentile : -10.6977561951\n", + " log-sigma-5-0-mm-3D_Minimum : -347.345001221\n", + " log-sigma-5-0-mm-3D_RobustMeanAbsoluteDeviation : 43.2562957783\n", + " log-sigma-5-0-mm-3D_Mean : -105.265625411\n", + " log-sigma-1-0-mm-3D_RootMeanSquared : 1978.94740333\n", " log-sigma-1-0-mm-3D_Energy : 16201455197.6\n", - " log-sigma-1-0-mm-3D_RobustMeanAbsoluteDeviation : 34.3094515237\n", - " log-sigma-1-0-mm-3D_Median : -18.9197921753\n", - " log-sigma-1-0-mm-3D_TotalEnergy : 64275792715.1\n", + " log-sigma-1-0-mm-3D_Uniformity : 0.114235313372\n", " log-sigma-1-0-mm-3D_Maximum : 164.726760864\n", - " log-sigma-1-0-mm-3D_RootMeanSquared : 1978.94740333\n", - " log-sigma-1-0-mm-3D_90Percentile : 54.7903442383\n", - " log-sigma-1-0-mm-3D_Minimum : -255.259628296\n", - " log-sigma-1-0-mm-3D_Entropy : 3.37004955078\n", - " log-sigma-1-0-mm-3D_StandardDeviation : 62.6969503974\n", " log-sigma-1-0-mm-3D_Range : 419.98638916\n", + " log-sigma-1-0-mm-3D_Skewness : -0.220905251704\n", + " log-sigma-1-0-mm-3D_Kurtosis : 3.07182438072\n", + " log-sigma-1-0-mm-3D_Median : -18.9197921753\n", " log-sigma-1-0-mm-3D_Variance : 3930.90758913\n", " log-sigma-1-0-mm-3D_10Percentile : -104.93405304\n", - " log-sigma-1-0-mm-3D_Kurtosis : 3.07182438072\n", + " log-sigma-1-0-mm-3D_Entropy : 3.37004955078\n", + " log-sigma-1-0-mm-3D_TotalEnergy : 64275792715.1\n", + " log-sigma-1-0-mm-3D_InterquartileRange : 81.8767185211\n", + " log-sigma-1-0-mm-3D_MeanAbsoluteDeviation : 49.6646616511\n", + " log-sigma-1-0-mm-3D_StandardDeviation : 62.6969503974\n", + " log-sigma-1-0-mm-3D_90Percentile : 54.7903442383\n", + " log-sigma-1-0-mm-3D_Minimum : -255.259628296\n", + " log-sigma-1-0-mm-3D_RobustMeanAbsoluteDeviation : 34.3094515237\n", " log-sigma-1-0-mm-3D_Mean : -22.0460274432\n", - " log-sigma-5-0-mm-3D_InterquartileRange : 106.342716217\n", - " log-sigma-5-0-mm-3D_Skewness : -0.30549686903\n", - " log-sigma-5-0-mm-3D_Uniformity : 0.0902675928609\n", - " log-sigma-5-0-mm-3D_MeanAbsoluteDeviation : 63.4364264458\n", - " log-sigma-5-0-mm-3D_Energy : 14878729370.4\n", - " log-sigma-5-0-mm-3D_RobustMeanAbsoluteDeviation : 43.2562957783\n", - " log-sigma-5-0-mm-3D_Median : -99.1174468994\n", - " log-sigma-5-0-mm-3D_TotalEnergy : 59028162175.1\n", - " log-sigma-5-0-mm-3D_Maximum : 117.414512634\n", - " log-sigma-5-0-mm-3D_RootMeanSquared : 1896.44460614\n", - " log-sigma-5-0-mm-3D_90Percentile : -10.6977561951\n", - " log-sigma-5-0-mm-3D_Minimum : -347.345001221\n", - " log-sigma-5-0-mm-3D_Entropy : 3.71336391413\n", - " log-sigma-5-0-mm-3D_StandardDeviation : 80.5220089107\n", - " log-sigma-5-0-mm-3D_Range : 464.759513855\n", - " log-sigma-5-0-mm-3D_Variance : 6483.79391901\n", - " log-sigma-5-0-mm-3D_10Percentile : -211.974316406\n", - " log-sigma-5-0-mm-3D_Kurtosis : 3.11489160873\n", - " log-sigma-5-0-mm-3D_Mean : -105.265625411\n" + " log-sigma-3-0-mm-3D_RootMeanSquared : 1919.01616706\n", + " log-sigma-3-0-mm-3D_Energy : 15235011555.6\n", + " log-sigma-3-0-mm-3D_Uniformity : 0.0906478492348\n", + " log-sigma-3-0-mm-3D_Maximum : 114.296691895\n", + " log-sigma-3-0-mm-3D_Range : 468.63192749\n", + " log-sigma-3-0-mm-3D_Skewness : -0.498386343995\n", + " log-sigma-3-0-mm-3D_Kurtosis : 3.18336583197\n", + " log-sigma-3-0-mm-3D_Median : -73.3129653931\n", + " log-sigma-3-0-mm-3D_Variance : 6720.06651871\n", + " log-sigma-3-0-mm-3D_10Percentile : -197.017340088\n", + " log-sigma-3-0-mm-3D_Entropy : 3.72121444058\n", + " log-sigma-3-0-mm-3D_TotalEnergy : 60441635199.8\n", + " log-sigma-3-0-mm-3D_InterquartileRange : 103.158138275\n", + " log-sigma-3-0-mm-3D_MeanAbsoluteDeviation : 64.3312024633\n", + " log-sigma-3-0-mm-3D_StandardDeviation : 81.9760118492\n", + " log-sigma-3-0-mm-3D_90Percentile : 13.9173410416\n", + " log-sigma-3-0-mm-3D_Minimum : -354.335235596\n", + " log-sigma-3-0-mm-3D_RobustMeanAbsoluteDeviation : 43.3779243984\n", + " log-sigma-3-0-mm-3D_Mean : -82.7355469484\n" ] } ], "source": [ "# Show result\n", - "for sigma, features in logFeatures.iteritems():\n", - " for (key, val) in features.iteritems():\n", + "for sigma, features in logFeatures.items():\n", + " for (key, val) in features.items():\n", " laplacianFeatureName = '%s_%s' % (str(sigma), key)\n", - " print ' ', laplacianFeatureName, ':', val" + " print(' ', laplacianFeatureName, ':', val)" ] }, { @@ -1153,7 +1199,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 23, "metadata": { "collapsed": false }, @@ -1162,12 +1208,12 @@ "name": "stdout", "output_type": "stream", "text": [ - "Calculated firstorder features with wavelet-LHL\n", - "Calculated firstorder features with wavelet-LHH\n", "Calculated firstorder features with wavelet-HLL\n", + "Calculated firstorder features with wavelet-LHH\n", + "Calculated firstorder features with wavelet-HHH\n", + "Calculated firstorder features with wavelet-LHL\n", "Calculated firstorder features with wavelet-LLH\n", "Calculated firstorder features with wavelet-HLH\n", - "Calculated firstorder features with wavelet-HHH\n", "Calculated firstorder features with wavelet-HHL\n", "Calculated firstorder features with wavelet-LLL\n" ] @@ -1175,19 +1221,19 @@ ], "source": [ "waveletFeatures = {}\n", - "for decompositionImage, decompositionName, inputKwargs in imageoperations.applyFilterWavelet(image):\n", + "for decompositionImage, decompositionName, inputKwargs in imageoperations.getWaveletImage(image):\n", " decompositionImage, croppedMask, bb = imageoperations.cropToTumorMask(decompositionImage, mask)\n", " waveletFirstOrderFeaturs = firstorder.RadiomicsFirstOrder(decompositionImage, croppedMask, **kwargs)\n", " waveletFirstOrderFeaturs.enableAllFeatures()\n", " waveletFirstOrderFeaturs.calculateFeatures()\n", "\n", - " print 'Calculated firstorder features with ', decompositionName\n", + " print('Calculated firstorder features with ', decompositionName)\n", " waveletFeatures[decompositionName] = waveletFirstOrderFeaturs.featureValues" ] }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 24, "metadata": { "collapsed": false }, @@ -1196,187 +1242,197 @@ "name": "stdout", "output_type": "stream", "text": [ - " wavelet-LLL_InterquartileRange : 139.421191409\n", - " wavelet-LLL_Skewness : -0.602284216139\n", - " wavelet-LLL_Uniformity : 0.0803482068616\n", - " wavelet-LLL_MeanAbsoluteDeviation : 74.7767053453\n", - " wavelet-LLL_Energy : 51254818952.9\n", - " wavelet-LLL_RobustMeanAbsoluteDeviation : 55.382748498\n", - " wavelet-LLL_Median : 1525.11598422\n", - " wavelet-LLL_TotalEnergy : 203342482418.0\n", - " wavelet-LLL_Maximum : 1699.41321411\n", - " wavelet-LLL_RootMeanSquared : 3519.85352748\n", - " wavelet-LLL_90Percentile : 1630.40959406\n", - " wavelet-LLL_Minimum : 1101.29425235\n", - " wavelet-LLL_Entropy : 3.81186803941\n", - " wavelet-LLL_StandardDeviation : 91.2394927085\n", - " wavelet-LLL_Range : 598.118961757\n", - " wavelet-LLL_Variance : 8324.64502971\n", - " wavelet-LLL_10Percentile : 1408.32497169\n", - " wavelet-LLL_Kurtosis : 3.30562101996\n", - " wavelet-LLL_Mean : 1518.67080158\n", - " wavelet-HHH_InterquartileRange : 10.9326520923\n", - " wavelet-HHH_Skewness : -0.161302587938\n", - " wavelet-HHH_Uniformity : 0.486414452921\n", - " wavelet-HHH_MeanAbsoluteDeviation : 6.88788741453\n", - " wavelet-HHH_Energy : 16547974728.9\n", - " wavelet-HHH_RobustMeanAbsoluteDeviation : 4.54697240555\n", - " wavelet-HHH_Median : 0.0513263224352\n", - " wavelet-HHH_TotalEnergy : 65650534507.8\n", - " wavelet-HHH_Maximum : 59.9134724023\n", - " wavelet-HHH_RootMeanSquared : 1999.99847286\n", - " wavelet-HHH_90Percentile : 10.735432567\n", - " wavelet-HHH_Minimum : -58.0273629729\n", - " wavelet-HHH_Entropy : 1.11204797433\n", - " wavelet-HHH_StandardDeviation : 9.19944859408\n", - " wavelet-HHH_Range : 117.940835375\n", - " wavelet-HHH_Variance : 84.6298544352\n", - " wavelet-HHH_10Percentile : -10.6879329892\n", - " wavelet-HHH_Kurtosis : 6.35651924152\n", - " wavelet-HHH_Mean : -0.0226847341909\n", - " wavelet-HLL_InterquartileRange : 11.2243394312\n", - " wavelet-HLL_Skewness : 0.206551182686\n", - " wavelet-HLL_Uniformity : 0.48329527556\n", - " wavelet-HLL_MeanAbsoluteDeviation : 7.05950814555\n", - " wavelet-HLL_Energy : 16547158112.3\n", - " wavelet-HLL_RobustMeanAbsoluteDeviation : 4.68136820947\n", - " wavelet-HLL_Median : -0.196353934925\n", - " wavelet-HLL_TotalEnergy : 65647294757.0\n", - " wavelet-HLL_Maximum : 74.8590093632\n", - " wavelet-HLL_RootMeanSquared : 1999.94912386\n", - " wavelet-HLL_90Percentile : 10.9187592195\n", - " wavelet-HLL_Minimum : -51.9965483949\n", - " wavelet-HLL_Entropy : 1.13005458526\n", - " wavelet-HLL_StandardDeviation : 9.42063441708\n", - " wavelet-HLL_Range : 126.855557758\n", - " wavelet-HLL_Variance : 88.7483528203\n", - " wavelet-HLL_10Percentile : -11.1822447049\n", - " wavelet-HLL_Kurtosis : 6.44193937557\n", - " wavelet-HLL_Mean : -0.0730639190171\n", - " wavelet-HHL_InterquartileRange : 11.4885048182\n", - " wavelet-HHL_Skewness : 0.00173347436935\n", - " wavelet-HHL_Uniformity : 0.482438705425\n", - " wavelet-HHL_MeanAbsoluteDeviation : 7.09468688619\n", - " wavelet-HHL_Energy : 16548297953.4\n", - " wavelet-HHL_RobustMeanAbsoluteDeviation : 4.73465210477\n", - " wavelet-HHL_Median : 0.0731800928294\n", - " wavelet-HHL_TotalEnergy : 65651816831.6\n", - " wavelet-HHL_Maximum : 52.750446198\n", - " wavelet-HHL_RootMeanSquared : 2000.01800532\n", - " wavelet-HHL_90Percentile : 11.1168222752\n", - " wavelet-HHL_Minimum : -52.3423184536\n", - " wavelet-HHL_Entropy : 1.13367844225\n", - " wavelet-HHL_StandardDeviation : 9.38156375064\n", - " wavelet-HHL_Range : 105.092764652\n", - " wavelet-HHL_Variance : 88.0137384072\n", - " wavelet-HHL_10Percentile : -11.1708244039\n", - " wavelet-HHL_Kurtosis : 5.24887979579\n", - " wavelet-HHL_Mean : -0.00399803756091\n", - " wavelet-LLH_InterquartileRange : 51.7485179102\n", - " wavelet-LLH_Skewness : -0.514193775328\n", - " wavelet-LLH_Uniformity : 0.182181892142\n", - " wavelet-LLH_MeanAbsoluteDeviation : 31.7641825492\n", - " wavelet-LLH_Energy : 16405200866.5\n", - " wavelet-LLH_RobustMeanAbsoluteDeviation : 21.5262080555\n", - " wavelet-LLH_Median : -7.1948286426\n", - " wavelet-LLH_TotalEnergy : 65084109883.0\n", - " wavelet-LLH_Maximum : 167.364402698\n", - " wavelet-LLH_RootMeanSquared : 1991.35191339\n", - " wavelet-LLH_90Percentile : 38.2699123752\n", - " wavelet-LLH_Minimum : -209.872439978\n", - " wavelet-LLH_Entropy : 2.73966669562\n", - " wavelet-LLH_StandardDeviation : 41.4892105786\n", - " wavelet-LLH_Range : 377.236842676\n", - " wavelet-LLH_Variance : 1721.35459443\n", - " wavelet-LLH_10Percentile : -58.0702381448\n", - " wavelet-LLH_Kurtosis : 4.92884123547\n", - " wavelet-LLH_Mean : -9.08034105832\n", - " wavelet-HLH_InterquartileRange : 10.99821242\n", - " wavelet-HLH_Skewness : -0.216428246439\n", - " wavelet-HLH_Uniformity : 0.488298907219\n", - " wavelet-HLH_MeanAbsoluteDeviation : 6.77388628528\n", - " wavelet-HLH_Energy : 16547339501.6\n", - " wavelet-HLH_RobustMeanAbsoluteDeviation : 4.48592652835\n", - " wavelet-HLH_Median : -0.065165818915\n", - " wavelet-HLH_TotalEnergy : 65648014380.2\n", - " wavelet-HLH_Maximum : 54.031233446\n", - " wavelet-HLH_RootMeanSquared : 1999.96008551\n", - " wavelet-HLH_90Percentile : 10.5580383627\n", - " wavelet-HLH_Minimum : -59.7402845962\n", - " wavelet-HLH_Entropy : 1.09951676451\n", - " wavelet-HLH_StandardDeviation : 9.02836267104\n", - " wavelet-HLH_Range : 113.771518042\n", - " wavelet-HLH_Variance : 81.5113325198\n", - " wavelet-HLH_10Percentile : -10.5831673374\n", - " wavelet-HLH_Kurtosis : 6.47263183683\n", - " wavelet-HLH_Mean : -0.0602928335869\n", - " wavelet-LHL_InterquartileRange : 11.2243394312\n", - " wavelet-LHL_Skewness : 0.206551182686\n", - " wavelet-LHL_Uniformity : 0.48329527556\n", - " wavelet-LHL_MeanAbsoluteDeviation : 7.05950814555\n", - " wavelet-LHL_Energy : 16547158112.3\n", - " wavelet-LHL_RobustMeanAbsoluteDeviation : 4.68136820947\n", - " wavelet-LHL_Median : -0.196353934925\n", - " wavelet-LHL_TotalEnergy : 65647294757.0\n", - " wavelet-LHL_Maximum : 74.8590093632\n", - " wavelet-LHL_RootMeanSquared : 1999.94912386\n", - " wavelet-LHL_90Percentile : 10.9187592195\n", - " wavelet-LHL_Minimum : -51.9965483949\n", - " wavelet-LHL_Entropy : 1.13005458526\n", - " wavelet-LHL_StandardDeviation : 9.42063441708\n", - " wavelet-LHL_Range : 126.855557758\n", - " wavelet-LHL_Variance : 88.7483528203\n", - " wavelet-LHL_10Percentile : -11.1822447049\n", - " wavelet-LHL_Kurtosis : 6.44193937557\n", - " wavelet-LHL_Mean : -0.0730639190171\n", - " wavelet-LHH_InterquartileRange : 10.99821242\n", - " wavelet-LHH_Skewness : -0.216428246439\n", - " wavelet-LHH_Uniformity : 0.488298907219\n", - " wavelet-LHH_MeanAbsoluteDeviation : 6.77388628528\n", - " wavelet-LHH_Energy : 16547339501.6\n", - " wavelet-LHH_RobustMeanAbsoluteDeviation : 4.48592652835\n", - " wavelet-LHH_Median : -0.0651658189149\n", - " wavelet-LHH_TotalEnergy : 65648014380.2\n", - " wavelet-LHH_Maximum : 54.031233446\n", - " wavelet-LHH_RootMeanSquared : 1999.96008551\n", - " wavelet-LHH_90Percentile : 10.5580383627\n", - " wavelet-LHH_Minimum : -59.7402845962\n", - " wavelet-LHH_Entropy : 1.09951676451\n", - " wavelet-LHH_StandardDeviation : 9.02836267104\n", - " wavelet-LHH_Range : 113.771518042\n", - " wavelet-LHH_Variance : 81.5113325198\n", - " wavelet-LHH_10Percentile : -10.5831673374\n", - " wavelet-LHH_Kurtosis : 6.47263183683\n", - " wavelet-LHH_Mean : -0.0602928335869\n" + " wavelet-HLH_RootMeanSquared : 2000.3397095\n", + " wavelet-HLH_Energy : 16553621990.3\n", + " wavelet-HLH_Uniformity : 0.192969183516\n", + " wavelet-HLH_Maximum : 195.252851267\n", + " wavelet-HLH_Range : 449.325547601\n", + " wavelet-HLH_Skewness : -0.109634215846\n", + " wavelet-HLH_Kurtosis : 5.96264006105\n", + " wavelet-HLH_Median : -0.788893809524\n", + " wavelet-HLH_Variance : 1812.89759077\n", + " wavelet-HLH_10Percentile : -48.7973652241\n", + " wavelet-HLH_Entropy : 2.75501833527\n", + " wavelet-HLH_TotalEnergy : 65672938804.3\n", + " wavelet-HLH_InterquartileRange : 44.1166822627\n", + " wavelet-HLH_MeanAbsoluteDeviation : 30.6419982661\n", + " wavelet-HLH_StandardDeviation : 42.5781351255\n", + " wavelet-HLH_90Percentile : 48.8399961041\n", + " wavelet-HLH_Minimum : -254.072696334\n", + " wavelet-HLH_RobustMeanAbsoluteDeviation : 18.8328798407\n", + " wavelet-HLH_Mean : -0.113489262994\n", + " wavelet-HLL_RootMeanSquared : 1995.50607096\n", + " wavelet-HLL_Energy : 16473718010.5\n", + " wavelet-HLL_Uniformity : 0.163587425574\n", + " wavelet-HLL_Maximum : 186.246123128\n", + " wavelet-HLL_Range : 477.790085389\n", + " wavelet-HLL_Skewness : -0.514166044802\n", + " wavelet-HLL_Kurtosis : 5.09932613055\n", + " wavelet-HLL_Median : -2.81720035764\n", + " wavelet-HLL_Variance : 2328.11665966\n", + " wavelet-HLL_10Percentile : -62.825323625\n", + " wavelet-HLL_Entropy : 2.95573220857\n", + " wavelet-HLL_TotalEnergy : 65355936931.4\n", + " wavelet-HLL_InterquartileRange : 53.6721220044\n", + " wavelet-HLL_MeanAbsoluteDeviation : 35.7539421526\n", + " wavelet-HLL_StandardDeviation : 48.2505612367\n", + " wavelet-HLL_90Percentile : 50.858801791\n", + " wavelet-HLL_Minimum : -291.543962261\n", + " wavelet-HLL_RobustMeanAbsoluteDeviation : 22.7497539081\n", + " wavelet-HLL_Mean : -5.07735424173\n", + " wavelet-LHH_RootMeanSquared : 1999.33891946\n", + " wavelet-LHH_Energy : 16537062247.2\n", + " wavelet-LHH_Uniformity : 0.140809788318\n", + " wavelet-LHH_Maximum : 279.350380756\n", + " wavelet-LHH_Range : 604.053834439\n", + " wavelet-LHH_Skewness : 0.197382131363\n", + " wavelet-LHH_Kurtosis : 5.10438678184\n", + " wavelet-LHH_Median : -1.94009209997\n", + " wavelet-LHH_Variance : 3189.24714715\n", + " wavelet-LHH_10Percentile : -69.1252699081\n", + " wavelet-LHH_Entropy : 3.17918664471\n", + " wavelet-LHH_TotalEnergy : 65607241581.1\n", + " wavelet-LHH_InterquartileRange : 61.7174514323\n", + " wavelet-LHH_MeanAbsoluteDeviation : 41.6368845931\n", + " wavelet-LHH_StandardDeviation : 56.4734198287\n", + " wavelet-LHH_90Percentile : 63.2151706827\n", + " wavelet-LHH_Minimum : -324.703453682\n", + " wavelet-LHH_RobustMeanAbsoluteDeviation : 26.4723285429\n", + " wavelet-LHH_Mean : -1.45881510799\n", + " wavelet-LHL_RootMeanSquared : 1995.91519044\n", + " wavelet-LHL_Energy : 16480473600.0\n", + " wavelet-LHL_Uniformity : 0.121366697967\n", + " wavelet-LHL_Maximum : 286.571219987\n", + " wavelet-LHL_Range : 641.465953025\n", + " wavelet-LHL_Skewness : -0.369538595422\n", + " wavelet-LHL_Kurtosis : 4.82046635261\n", + " wavelet-LHL_Median : -4.09721168383\n", + " wavelet-LHL_Variance : 4432.09816024\n", + " wavelet-LHL_10Percentile : -85.6408963111\n", + " wavelet-LHL_Entropy : 3.40407739189\n", + " wavelet-LHL_TotalEnergy : 65382738281.1\n", + " wavelet-LHL_InterquartileRange : 71.4997770702\n", + " wavelet-LHL_MeanAbsoluteDeviation : 48.9628822529\n", + " wavelet-LHL_StandardDeviation : 66.5740051389\n", + " wavelet-LHL_90Percentile : 71.5796532291\n", + " wavelet-LHL_Minimum : -354.894733038\n", + " wavelet-LHL_RobustMeanAbsoluteDeviation : 30.6452121553\n", + " wavelet-LHL_Mean : -5.19541075848\n", + " wavelet-HHL_RootMeanSquared : 2000.43345645\n", + " wavelet-HHL_Energy : 16555173614.7\n", + " wavelet-HHL_Uniformity : 0.358701481744\n", + " wavelet-HHL_Maximum : 96.9275598214\n", + " wavelet-HHL_Range : 197.650791431\n", + " wavelet-HHL_Skewness : 0.121890250304\n", + " wavelet-HHL_Kurtosis : 4.71302154772\n", + " wavelet-HHL_Median : 0.0829386441652\n", + " wavelet-HHL_Variance : 371.536288126\n", + " wavelet-HHL_10Percentile : -22.0062020433\n", + " wavelet-HHL_Entropy : 1.75422760497\n", + " wavelet-HHL_TotalEnergy : 65679094540.6\n", + " wavelet-HHL_InterquartileRange : 22.3805938159\n", + " wavelet-HHL_MeanAbsoluteDeviation : 14.4086961805\n", + " wavelet-HHL_StandardDeviation : 19.2752766031\n", + " wavelet-HHL_90Percentile : 23.0361222477\n", + " wavelet-HHL_Minimum : -100.72323161\n", + " wavelet-HHL_RobustMeanAbsoluteDeviation : 9.30098915932\n", + " wavelet-HHL_Mean : 0.340590352112\n", + " wavelet-LLH_RootMeanSquared : 2025.7276121\n", + " wavelet-LLH_Energy : 16976478846.8\n", + " wavelet-LLH_Uniformity : 0.0304399667913\n", + " wavelet-LLH_Maximum : 733.850508276\n", + " wavelet-LLH_Range : 1516.85940092\n", + " wavelet-LLH_Skewness : -0.525773815287\n", + " wavelet-LLH_Kurtosis : 2.69674899921\n", + " wavelet-LLH_Median : 62.7368130339\n", + " wavelet-LLH_Variance : 63709.1700017\n", + " wavelet-LLH_10Percentile : -370.145218742\n", + " wavelet-LLH_Entropy : 5.27888924024\n", + " wavelet-LLH_TotalEnergy : 67350532534.4\n", + " wavelet-LLH_InterquartileRange : 352.67245821\n", + " wavelet-LLH_MeanAbsoluteDeviation : 205.422769392\n", + " wavelet-LLH_StandardDeviation : 252.406755064\n", + " wavelet-LLH_90Percentile : 297.911610403\n", + " wavelet-LLH_Minimum : -783.008892644\n", + " wavelet-LLH_RobustMeanAbsoluteDeviation : 146.79059076\n", + " wavelet-LLH_Mean : 9.94109078503\n", + " wavelet-LLL_RootMeanSquared : 4269.54365408\n", + " wavelet-LLL_Energy : 75413385469.3\n", + " wavelet-LLL_Uniformity : 0.0199077767278\n", + " wavelet-LLL_Maximum : 3180.63918677\n", + " wavelet-LLL_Range : 1712.56194574\n", + " wavelet-LLL_Skewness : 0.228846426465\n", + " wavelet-LLL_Kurtosis : 2.27365643067\n", + " wavelet-LLL_Median : 2244.88673609\n", + " wavelet-LLL_Variance : 122620.562796\n", + " wavelet-LLL_10Percentile : 1812.68473489\n", + " wavelet-LLL_Entropy : 5.78300489052\n", + " wavelet-LLL_TotalEnergy : 299186404755.0\n", + " wavelet-LLL_InterquartileRange : 550.594267427\n", + " wavelet-LLL_MeanAbsoluteDeviation : 293.143995944\n", + " wavelet-LLL_StandardDeviation : 350.172190209\n", + " wavelet-LLL_90Percentile : 2739.69052111\n", + " wavelet-LLL_Minimum : 1468.07724103\n", + " wavelet-LLL_RobustMeanAbsoluteDeviation : 220.739697172\n", + " wavelet-LLL_Mean : 2255.1595095\n", + " wavelet-HHH_RootMeanSquared : 2000.23985683\n", + " wavelet-HHH_Energy : 16551969388.8\n", + " wavelet-HHH_Uniformity : 0.382919979814\n", + " wavelet-HHH_Maximum : 76.4099650187\n", + " wavelet-HHH_Range : 151.165663688\n", + " wavelet-HHH_Skewness : -0.0688112737237\n", + " wavelet-HHH_Kurtosis : 4.32455549814\n", + " wavelet-HHH_Median : 0.109117292789\n", + " wavelet-HHH_Variance : 299.952218013\n", + " wavelet-HHH_10Percentile : -21.0383130256\n", + " wavelet-HHH_Entropy : 1.62781167475\n", + " wavelet-HHH_TotalEnergy : 65666382462.8\n", + " wavelet-HHH_InterquartileRange : 20.3192746422\n", + " wavelet-HHH_MeanAbsoluteDeviation : 13.0759756862\n", + " wavelet-HHH_StandardDeviation : 17.3191286736\n", + " wavelet-HHH_90Percentile : 20.9238433344\n", + " wavelet-HHH_Minimum : -74.7556986689\n", + " wavelet-HHH_RobustMeanAbsoluteDeviation : 8.53027450692\n", + " wavelet-HHH_Mean : 0.164876359429\n" ] } ], "source": [ "# Show result\n", - "for decompositionName, features in waveletFeatures.iteritems():\n", - " for (key, val) in features.iteritems():\n", + "for decompositionName, features in waveletFeatures.items():\n", + " for (key, val) in features.items():\n", " waveletFeatureName = '%s_%s' % (str(decompositionName), key)\n", - " print ' ', waveletFeatureName, ':', val" + " print(' ', waveletFeatureName, ':', val)" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] } ], "metadata": { + "anaconda-cloud": {}, "kernelspec": { - "display_name": "Python 2", + "display_name": "Python [conda root]", "language": "python", - "name": "python2" + "name": "conda-root-py" }, "language_info": { "codemirror_mode": { "name": "ipython", - "version": 2.0 + "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.11" + "pygments_lexer": "ipython3", + "version": "3.5.2" } }, "nbformat": 4, diff --git a/bin/Notebooks/helloRadiomics.ipynb b/bin/Notebooks/helloRadiomics.ipynb index 8b0e6bea..964d4be7 100644 --- a/bin/Notebooks/helloRadiomics.ipynb +++ b/bin/Notebooks/helloRadiomics.ipynb @@ -24,6 +24,7 @@ }, "outputs": [], "source": [ + "from __future__ import print_function, unicode_literals, division, absolute_import\n", "import sys\n", "import os\n", "import logging\n", @@ -96,9 +97,9 @@ "maskName = os.path.join(dataDir, testCase + '_label.nrrd')\n", "\n", "if not os.path.exists(imageName):\n", - " print 'Error: problem finding input image', imageName\n", + " print('Error: problem finding input image', imageName)\n", "if not os.path.exists(maskName):\n", - " print 'Error: problem finding input labelmap', maskName" + " print('Error: problem finding input labelmap', maskName)" ] }, { @@ -152,7 +153,7 @@ "output_type": "stream", "text": [ "Enabled input images:\n", - "\toriginal\n" + "\tOriginal\n" ] } ], @@ -172,9 +173,9 @@ "\n", "# extractor.enableInputImages(wavelet={}, log={'sigma':[3.0]})\n", "\n", - "print \"Enabled input images:\"\n", + "print(\"Enabled input images:\")\n", "for imageType in extractor.inputImages.keys():\n", - " print '\\t' + imageType" + " print('\\t' + imageType)" ] }, { @@ -246,6 +247,7 @@ "\n", " :math:`entropy = -\\displaystyle\\sum^{N_l}_{i=1}{p(i)\\log_2\\big(p(i)+\\epsilon\\big)}`\n", "\n", + " Here, :math:`\\epsilon` is an arbitrarily small positive number (:math:`\\approx 2.2\\times10^{-16}`).\n", " Entropy specifies the uncertainty/randomness in the\n", " image values. It measures the average amount of\n", " information required to encode the image values.\n", @@ -391,13 +393,13 @@ } ], "source": [ - "print \"Active features:\"\n", - "for cls, features in extractor.enabledFeatures.iteritems():\n", + "print(\"Active features:\")\n", + "for cls, features in extractor.enabledFeatures.items():\n", " if len(features) == 0:\n", " features = extractor.getFeatureNames(cls)\n", " for f in features:\n", - " print f\n", - " print eval('extractor.featureClasses[\"%s\"].get%sFeatureValue.__doc__' % (cls, f))" + " print(f)\n", + " print(eval('extractor.featureClasses[\"%s\"].get%sFeatureValue.__doc__' % (cls, f)))" ] }, { @@ -421,62 +423,63 @@ "Calculating features\n", "\t\tComputing firstorder\n", "Computed general_info_BoundingBox: (162; 84; 11; 47; 70; 7)\n", - "Computed general_info_GeneralSettings: {'verbose': True; 'binWidth': 25; 'label': 1; 'interpolator': 'sitkBSpline'; 'resampledPixelSpacing': None; 'padDistance': 5}\n", + "Computed general_info_GeneralSettings: {'label': 1; 'binWidth': 25; 'padDistance': 5; 'interpolator': 'sitkBSpline'; 'resampledPixelSpacing': None; 'verbose': True}\n", "Computed general_info_ImageHash: 5c9ce3ca174f0f8324aa4d277e0fef82dc5ac566\n", "Computed general_info_ImageSpacing: (0.7812499999999999; 0.7812499999999999; 6.499999999999998)\n", - "Computed general_info_InputImages: {'original': {}}\n", + "Computed general_info_InputImages: {'Original': {}}\n", "Computed general_info_MaskHash: 9dc2c3137b31fd872997d92c9a92d5178126d9d3\n", - "Computed general_info_Version: v1.0.post11.dev0+g610dffc\n", + "Computed general_info_Version: v1.0.1.post5.dev0+g72ac3cb\n", "Computed general_info_VolumeNum: 2\n", "Computed general_info_VoxelNum: 4137\n", - "Computed original_firstorder_InterquartileRange: 253.0\n", - "Computed original_firstorder_Skewness: 0.275650859086\n", - "Computed original_firstorder_Uniformity: 0.0451569635559\n", - "Computed original_firstorder_MeanAbsoluteDeviation: 133.447261953\n", - "Computed original_firstorder_Energy: 33122817481.0\n", - "Computed original_firstorder_RobustMeanAbsoluteDeviation: 103.00138343\n", "Computed original_firstorder_Median: 812.0\n", - "Computed original_firstorder_TotalEnergy: 131407662126.0\n", + "Computed original_firstorder_RobustMeanAbsoluteDeviation: 103.00138343\n", + "Computed original_firstorder_Skewness: 0.275650859086\n", + "Computed original_firstorder_InterquartileRange: 253.0\n", "Computed original_firstorder_Maximum: 1266.0\n", - "Computed original_firstorder_RootMeanSquared: 2829.57282108\n", - "Computed original_firstorder_90Percentile: 1044.4\n", - "Computed original_firstorder_Minimum: 468.0\n", - "Computed original_firstorder_Entropy: 4.6019355539\n", "Computed original_firstorder_StandardDeviation: 156.611235894\n", + "Computed original_firstorder_Minimum: 468.0\n", + "Computed original_firstorder_RootMeanSquared: 2829.57282108\n", "Computed original_firstorder_Range: 798.0\n", - "Computed original_firstorder_Variance: 24527.0792084\n", - "Computed original_firstorder_10Percentile: 632.0\n", "Computed original_firstorder_Kurtosis: 2.18077293939\n", - "Computed original_firstorder_Mean: 825.235436307\n" + "Computed original_firstorder_90Percentile: 1044.4\n", + "Computed original_firstorder_MeanAbsoluteDeviation: 133.447261953\n", + "Computed original_firstorder_TotalEnergy: 131407662126.0\n", + "Computed original_firstorder_10Percentile: 632.0\n", + "Computed original_firstorder_Mean: 825.235436307\n", + "Computed original_firstorder_Uniformity: 0.0451569635559\n", + "Computed original_firstorder_Energy: 33122817481.0\n", + "Computed original_firstorder_Variance: 24527.0792084\n", + "Computed original_firstorder_Entropy: 4.6019355539\n" ] } ], "source": [ - "print \"Calculating features\"\n", + "print(\"Calculating features\")\n", "featureVector = extractor.execute(imageName, maskName)\n", "\n", "for featureName in featureVector.keys():\n", - " print \"Computed %s: %s\" % (featureName, featureVector[featureName])" + " print(\"Computed %s: %s\" % (featureName, featureVector[featureName]))" ] } ], "metadata": { + "anaconda-cloud": {}, "kernelspec": { - "display_name": "Python 2", + "display_name": "Python [conda root]", "language": "python", - "name": "python2" + "name": "conda-root-py" }, "language_info": { "codemirror_mode": { "name": "ipython", - "version": 2 + "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.11" + "pygments_lexer": "ipython3", + "version": "3.5.2" } }, "nbformat": 4, diff --git a/bin/batchExamples/DatasetHierarchyReader.py b/bin/batchExamples/DatasetHierarchyReader.py index 35199dad..88bc521b 100644 --- a/bin/batchExamples/DatasetHierarchyReader.py +++ b/bin/batchExamples/DatasetHierarchyReader.py @@ -102,7 +102,7 @@ def findImageAndLabelPair(self, imageFilepaths, maskFilepaths, keywordSettings): conditions. """ - keywordSettings = {k: [str(keyword.strip()) for keyword in v.split(',')] for (k, v) in keywordSettings.iteritems()} + keywordSettings = {k: [str(keyword.strip()) for keyword in v.split(',')] for (k, v) in keywordSettings.items()} matchedImages = [] for imageFilepath in imageFilepaths: diff --git a/bin/batchExamples/GenerateInputCSV_Datasethierarchy.py b/bin/batchExamples/GenerateInputCSV_Datasethierarchy.py index 022fafe2..dd43c10c 100644 --- a/bin/batchExamples/GenerateInputCSV_Datasethierarchy.py +++ b/bin/batchExamples/GenerateInputCSV_Datasethierarchy.py @@ -1,3 +1,4 @@ +from __future__ import print_function, unicode_literals, division, absolute_import import os import csv from DatasetHierarchyReader import DatasetHierarchyReader @@ -15,12 +16,12 @@ def main(): keywordSettings['mask'] = 'label' keywordSettings['maskExclusion'] = '' - print "Scanning files..." + print("Scanning files...") datasetReader = DatasetHierarchyReader(inputDirectory, filetype=filetype) datasetHierarchyDict = datasetReader.ReadDatasetHierarchy() - print "Found %s patients, writing csv" % (str(len(datasetHierarchyDict.keys()))) + print("Found %s patients, writing csv" % (str(len(datasetHierarchyDict.keys())))) try: with open(outputFile, 'wb') as outFile: @@ -42,8 +43,8 @@ def main(): # ReaderName is not extracted using DatasetHierarchyReader, set it to 'N/A' cw.writerow([patientID, studyDate, 'N/A', imageFilepath, maskFilepath]) - except Exception, e: - print e + except Exception as e: + print(e) if __name__ == '__main__': diff --git a/bin/batchExamples/GenerateInputCSV_Filename.py b/bin/batchExamples/GenerateInputCSV_Filename.py index 35678c33..557f65b0 100644 --- a/bin/batchExamples/GenerateInputCSV_Filename.py +++ b/bin/batchExamples/GenerateInputCSV_Filename.py @@ -1,3 +1,4 @@ +from __future__ import print_function, unicode_literals, division, absolute_import import os import csv @@ -32,22 +33,22 @@ def main(): outputFile = DATA_ROOT_PATH + r"/Included/FileList.csv" filetype = ".nrrd" - print "Scanning files..." + print("Scanning files...") datasetHierarchyDict = scanpatients(inputDirectory, filetype) - print "Found %s patients, writing csv" % (len(datasetHierarchyDict.keys())) + print("Found %s patients, writing csv" % (len(datasetHierarchyDict.keys()))) try: with open(outputFile, 'wb') as outFile: cw = csv.writer(outFile, lineterminator='\n') - for patient, Studies in sorted(datasetHierarchyDict.iteritems(), key=lambda t: t[0]): - for Study, im_fileList in sorted(Studies['reconstructions'].iteritems(), key=lambda t: t[0]): + for patient, Studies in sorted(datasetHierarchyDict.items(), key=lambda t: t[0]): + for Study, im_fileList in sorted(Studies['reconstructions'].items(), key=lambda t: t[0]): for i_idx, im_file in enumerate(im_fileList): if Studies['segmentations'].has_key(Study): - for Reader, seg_fileList in sorted(Studies['segmentations'][Study].iteritems(), key=lambda t: t[0]): + for Reader, seg_fileList in sorted(Studies['segmentations'][Study].items(), key=lambda t: t[0]): for s_idx, seg_file in enumerate(sorted(seg_fileList)): i_name = Study @@ -57,8 +58,8 @@ def main(): if s_idx > 0: s_name += " (%s)" % (str(s_idx + 1)) cw.writerow([patient, i_name, s_name, im_file, seg_file]) - except Exception, e: - print e + except Exception as e: + print(e) def scanpatients(f, filetype): @@ -74,9 +75,9 @@ def scanpatients(f, filetype): outputDict[PtNo] = {'reconstructions': {}} outputDict[PtNo]['segmentations'] = {} - for SqKey, SqVal in SqDic.iteritems(): + for SqKey, SqVal in SqDic.items(): if ("ROI_" + SqVal) in fname: - for ReaderKey, ReaderVal in LabelDic.iteritems(): + for ReaderKey, ReaderVal in LabelDic.items(): if (ReaderKey + '_') in fname: if not outputDict[PtNo]['segmentations'].has_key(SqVal): outputDict[PtNo]['segmentations'][SqVal] = {} diff --git a/bin/helloFeatureClass.py b/bin/helloFeatureClass.py index 430920f2..8b8604f1 100644 --- a/bin/helloFeatureClass.py +++ b/bin/helloFeatureClass.py @@ -1,3 +1,4 @@ +from __future__ import print_function, unicode_literals, division, absolute_import import os import SimpleITK as sitk import numpy @@ -12,10 +13,10 @@ maskName = os.path.join(dataDir, testCase + '_label.nrrd') if not os.path.exists(imageName): - print 'Error: problem finding input image', imageName + print('Error: problem finding input image', imageName) exit() if not os.path.exists(maskName): - print 'Error: problem finding input image', maskName + print('Error: problem finding input image', maskName) exit() image = sitk.ReadImage(imageName) @@ -51,15 +52,15 @@ print 'Will calculate the following first order features: ' for f in firstOrderFeatures.enabledFeatures.keys(): - print ' ', f - print eval('firstOrderFeatures.get' + f + 'FeatureValue.__doc__') + print(' ', f) + print(eval('firstOrderFeatures.get' + f + 'FeatureValue.__doc__')) -print 'Calculating first order features...', +print('Calculating first order features...') firstOrderFeatures.calculateFeatures() -print 'done' +print('done') -print 'Calculated first order features: ' -for (key, val) in firstOrderFeatures.featureValues.iteritems(): +print('Calculated first order features: ') +for (key, val) in firstOrderFeatures.featureValues.items(): print ' ', key, ':', val # @@ -68,18 +69,18 @@ shapeFeatures = shape.RadiomicsShape(image, mask, **kwargs) shapeFeatures.enableAllFeatures() -print 'Will calculate the following Shape features: ' +print('Will calculate the following Shape features: ') for f in shapeFeatures.enabledFeatures.keys(): - print ' ', f - print eval('shapeFeatures.get' + f + 'FeatureValue.__doc__') + print(' ', f) + print(eval('shapeFeatures.get' + f + 'FeatureValue.__doc__')) -print 'Calculating Shape features...', +print('Calculating Shape features...') shapeFeatures.calculateFeatures() -print 'done' +print('done') -print 'Calculated Shape features: ' -for (key, val) in shapeFeatures.featureValues.iteritems(): - print ' ', key, ':', val +print('Calculated Shape features: ') +for (key, val) in shapeFeatures.featureValues.items(): + print(' ', key, ':', val) # # Show GLCM features @@ -87,18 +88,18 @@ glcmFeatures = glcm.RadiomicsGLCM(image, mask, **kwargs) glcmFeatures.enableAllFeatures() -print 'Will calculate the following GLCM features: ' +print('Will calculate the following GLCM features: ') for f in glcmFeatures.enabledFeatures.keys(): - print ' ', f - print eval('glcmFeatures.get' + f + 'FeatureValue.__doc__') + print(' ', f) + print(eval('glcmFeatures.get' + f + 'FeatureValue.__doc__')) -print 'Calculating GLCM features...', +print('Calculating GLCM features...') glcmFeatures.calculateFeatures() -print 'done' +print('done') -print 'Calculated GLCM features: ' -for (key, val) in glcmFeatures.featureValues.iteritems(): - print ' ', key, ':', val +print('Calculated GLCM features: ') +for (key, val) in glcmFeatures.featureValues.items(): + print(' ', key, ':', val) # # Show GLRLM features @@ -106,18 +107,18 @@ glrlmFeatures = glrlm.RadiomicsGLRLM(image, mask, **kwargs) glrlmFeatures.enableAllFeatures() -print 'Will calculate the following GLRLM features: ' +print('Will calculate the following GLRLM features: ') for f in glrlmFeatures.enabledFeatures.keys(): - print ' ', f - print eval('glrlmFeatures.get' + f + 'FeatureValue.__doc__') + print(' ', f) + print(eval('glrlmFeatures.get' + f + 'FeatureValue.__doc__')) -print 'Calculating GLRLM features...', +print('Calculating GLRLM features...') glrlmFeatures.calculateFeatures() -print 'done' +print('done') -print 'Calculated GLRLM features: ' -for (key, val) in glrlmFeatures.featureValues.iteritems(): - print ' ', key, ':', val +print('Calculated GLRLM features: ') +for (key, val) in glrlmFeatures.featureValues.items(): + print(' ', key, ':', val) # # Show GLSZM features @@ -125,18 +126,18 @@ glszmFeatures = glszm.RadiomicsGLSZM(image, mask, **kwargs) glszmFeatures.enableAllFeatures() -print 'Will calculate the following GLSZM features: ' +print('Will calculate the following GLSZM features: ') for f in glszmFeatures.enabledFeatures.keys(): - print ' ', f - print eval('glszmFeatures.get' + f + 'FeatureValue.__doc__') + print(' ', f) + print(eval('glszmFeatures.get' + f + 'FeatureValue.__doc__')) -print 'Calculating GLSZM features...', +print('Calculating GLSZM features...') glszmFeatures.calculateFeatures() -print 'done' +print('done') -print 'Calculated GLSZM features: ' -for (key, val) in glszmFeatures.featureValues.iteritems(): - print ' ', key, ':', val +print('Calculated GLSZM features: ') +for (key, val) in glszmFeatures.featureValues.items(): + print(' ', key, ':', val) # # Show FirstOrder features, calculated on a LoG filtered image @@ -147,9 +148,9 @@ logFirstorderFeatures = firstorder.RadiomicsFirstOrder(logImage, mask, **inputKwargs) logFirstorderFeatures.enableAllFeatures() logFirstorderFeatures.calculateFeatures() - for (key, val) in logFirstorderFeatures.featureValues.iteritems(): + for (key, val) in logFirstorderFeatures.featureValues.items(): laplacianFeatureName = '%s_%s' % (inputImageName, key) - print ' ', laplacianFeatureName, ':', val + print(' ', laplacianFeatureName, ':', val) # # Show FirstOrder features, calculated on a wavelet filtered image # @@ -158,7 +159,7 @@ waveletFirstOrderFeaturs = firstorder.RadiomicsFirstOrder(decompositionImage, mask, **inputKwargs) waveletFirstOrderFeaturs.enableAllFeatures() waveletFirstOrderFeaturs.calculateFeatures() - print 'Calculated firstorder features with wavelet ', decompositionName - for (key, val) in waveletFirstOrderFeaturs.featureValues.iteritems(): + print('Calculated firstorder features with wavelet ', decompositionName) + for (key, val) in waveletFirstOrderFeaturs.featureValues.items(): waveletFeatureName = 'wavelet-%s_%s' % (str(decompositionName), key) - print ' ', waveletFeatureName, ':', val + print(' ', waveletFeatureName, ':', val) diff --git a/bin/helloRadiomics.py b/bin/helloRadiomics.py index e476f621..74c0ae67 100644 --- a/bin/helloRadiomics.py +++ b/bin/helloRadiomics.py @@ -54,7 +54,7 @@ logger.addHandler(handler) print "Active features:" -for cls, features in extractor.enabledFeatures.iteritems(): +for cls, features in extractor.enabledFeatures.items(): if len(features) == 0: features = extractor.getFeatureNames(cls) for f in features: diff --git a/data/schemaFuncs.py b/data/schemaFuncs.py index 80765fe2..708e027e 100644 --- a/data/schemaFuncs.py +++ b/data/schemaFuncs.py @@ -1,11 +1,12 @@ import pywt from radiomics.featureextractor import RadiomicsFeaturesExtractor +from radiomics import c_str_type featureClasses = RadiomicsFeaturesExtractor.getFeatureClasses() def checkWavelet(value, rule_obj, path): - if not isinstance(value, basestring): + if not isinstance(value, c_str_type): raise TypeError('Wavelet not expected type (str)') wavelist = pywt.wavelist() if value not in wavelist: @@ -16,7 +17,7 @@ def checkWavelet(value, rule_obj, path): def checkInterpolator(value, rule_obj, path): if value is None: return True - if isinstance(value, basestring): + if isinstance(value, c_str_type): enum = {'sitkNearestNeighbor', 'sitkLinear', 'sitkBSpline', @@ -40,7 +41,7 @@ def checkInterpolator(value, rule_obj, path): def checkWeighting(value, rule_obj, path): if value is None: return True - elif isinstance(value, basestring): + elif isinstance(value, c_str_type): enum = ['euclidean', 'manhattan', 'infinity', 'no_weighting'] if value not in enum: raise ValueError('WeightingNorm value "%s" not valid, possible values: %s' % (value, enum)) @@ -53,7 +54,7 @@ def checkFeatureClass(value, rule_obj, path): global featureClasses if value is None: raise TypeError('featureClass dictionary cannot be None value') - for className, features in value.iteritems(): + for className, features in value.items(): if className not in featureClasses.keys(): raise ValueError( 'Feature Class %s is not recognized. Available feature classes are %s' % (className, featureClasses.keys())) diff --git a/radiomics/__init__.py b/radiomics/__init__.py index d7625fbd..e4503fc9 100644 --- a/radiomics/__init__.py +++ b/radiomics/__init__.py @@ -7,10 +7,12 @@ if in_py3: c_str_type = str - safe_xrange = lambda x: iter(range(x)) + safe_xrange = lambda *x,**kwargs: iter(range(*x, **kwargs)) + safe_cmp = lambda a,b: (a>b)-(a 0, diags)) diff --git a/radiomics/imageoperations.py b/radiomics/imageoperations.py index c794e4c4..2f04c9a3 100644 --- a/radiomics/imageoperations.py +++ b/radiomics/imageoperations.py @@ -4,6 +4,7 @@ import SimpleITK as sitk import numpy import pywt +from radiomics import safe_xrange logger = logging.getLogger(__name__) @@ -64,11 +65,11 @@ def generateAngles(size, maxDistance=1): angles = [] - for z in xrange(1, maxDistance + 1): + for z in safe_xrange(1, maxDistance + 1): angles.append((0, 0, z)) - for y in xrange(-maxDistance, maxDistance + 1): + for y in safe_xrange(-maxDistance, maxDistance + 1): angles.append((0, z, y)) - for x in xrange(-maxDistance, maxDistance + 1): + for x in safe_xrange(-maxDistance, maxDistance + 1): angles.append((z, y, x)) angles = numpy.array(angles) @@ -119,8 +120,13 @@ def cropToTumorMask(imageNode, maskNode, label=1, boundingBox=None): # Crop Image logger.debug('Cropping to size %s', (boundingBox[1::2] - boundingBox[0::2]) + 1) cif = sitk.CropImageFilter() - cif.SetLowerBoundaryCropSize(ijkMinBounds) - cif.SetUpperBoundaryCropSize(ijkMaxBounds) + try: + cif.SetLowerBoundaryCropSize(ijkMinBounds) + cif.SetUpperBoundaryCropSize(ijkMaxBounds) + except TypeError: + # newer versions of SITK/python want a tuple or list + cif.SetLowerBoundaryCropSize(ijkMinBounds.tolist()) + cif.SetUpperBoundaryCropSize(ijkMaxBounds.tolist()) croppedImageNode = cif.Execute(imageNode) croppedMaskNode = cif.Execute(maskNode) @@ -391,7 +397,7 @@ def _swt3(inputImage, wavelet="coif1", level=1, start_level=0): 'LHH': LHH, 'LHL': LHL, 'LLH': LLH} - for decName, decImage in dec.iteritems(): + for decName, decImage in dec.items(): decTemp = decImage.copy() decTemp = numpy.resize(decTemp, original_shape) sitkImage = sitk.GetImageFromArray(decTemp) diff --git a/radiomics/scripts/commandline.py b/radiomics/scripts/commandline.py index 7a4ac506..ccff36d1 100644 --- a/radiomics/scripts/commandline.py +++ b/radiomics/scripts/commandline.py @@ -71,7 +71,7 @@ def main(): json.dump(featureVector, args.out) args.out.write('\n') else: - for k, v in featureVector.iteritems(): + for k, v in featureVector.items(): args.out.write('%s: %s\n' % (k, v)) except Exception: logging.error('FEATURE EXTRACTION FAILED:\n%s', traceback.format_exc()) diff --git a/radiomics/shape.py b/radiomics/shape.py index 23b9b152..c913d68e 100644 --- a/radiomics/shape.py +++ b/radiomics/shape.py @@ -1,7 +1,7 @@ import numpy import operator import collections -from radiomics import base, imageoperations +from radiomics import base, imageoperations, safe_xrange import SimpleITK as sitk @@ -27,8 +27,13 @@ def __init__(self, inputImage, inputMask, **kwargs): cpif = sitk.ConstantPadImageFilter() padding = numpy.tile(1, 3) - cpif.SetPadLowerBound(padding) - cpif.SetPadUpperBound(padding) + try: + cpif.SetPadLowerBound(padding) + cpif.SetPadUpperBound(padding) + except TypeError: + # newer versions of SITK/python want a tuple or list + cpif.SetPadLowerBound(padding.tolist()) + cpif.SetPadUpperBound(padding.tolist()) self.inputMask = cpif.Execute(self.inputMask) @@ -56,9 +61,9 @@ def _calculateSurfaceArea(self): S_A = 0.0 # iterate over all voxels which may border segmentation or are a part of it - for v_z in xrange(minBounds[0] - 1, maxBounds[0] + 1): - for v_y in xrange(minBounds[1] - 1, maxBounds[1] + 1): - for v_x in xrange(minBounds[2] - 1, maxBounds[2] + 1): + for v_z in safe_xrange(minBounds[0] - 1, maxBounds[0] + 1): + for v_y in safe_xrange(minBounds[1] - 1, maxBounds[1] + 1): + for v_x in safe_xrange(minBounds[2] - 1, maxBounds[2] + 1): # indices to corners of current sampling cube gridCell = gridAngles + [v_z, v_y, v_x] diff --git a/tests/testUtils.py b/tests/testUtils.py index 013c6748..ca94832c 100644 --- a/tests/testUtils.py +++ b/tests/testUtils.py @@ -7,7 +7,7 @@ import math import numpy from nose_parameterized import parameterized -from radiomics import imageoperations, in_py3 +from radiomics import imageoperations, in_py3, safe_cmp # Get the logger. This is done outside the class, as it is needed by both the class and the custom_name_func logger = logging.getLogger('testUtils') @@ -105,7 +105,7 @@ class or test case is changed, function returns True. self._featureClassName = className # Check if test settings have changed - if cmp(self._kwargs, self.getBaselineDict(className, testCase)) != 0: + if safe_cmp(self._kwargs, self.getBaselineDict(className, testCase)) != 0: self._kwargs = self.getBaselineDict(className, testCase) self._testCase = None # forces image to be reloaded (as settings have changed) @@ -247,6 +247,9 @@ def writeCSV(self, data, fileName): # get the headers from the first row header = sorted(data[list(data.keys())[0]].keys()) header = ['testCase'] + header + if in_py3: + # since csvWriter only supports bytes not str + header = [c_col.encode('ascii') for c_col in header] csvFileWriter.writerow(header) for testCase in sorted(data.keys()): thisCase = data[testCase] @@ -254,6 +257,9 @@ def writeCSV(self, data, fileName): row = [] for h in header: row = row + [thisCase[h]] + if in_py3: + # since csvWriter only supports bytes not str + row = [c_col.encode('ascii') for c_col in row] csvFileWriter.writerow(row) csvFile.close() self._logger.info('Wrote to file %s', fileName) From 7b80424d4b931c3f6868551d85f26fa1d7927b3d Mon Sep 17 00:00:00 2001 From: Joost van Griethuysen Date: Fri, 10 Feb 2017 14:07:46 +0100 Subject: [PATCH 3/6] BUG: Fix zip() bug in shape.py In python 3, the zip function returns a 'zip' object, similar to python generators. This does not change it's implementation in python for loops, but it is not evaluated if it is used to generate a numpy array. Therefore, add a cast to list, which evaluates the object, before assigning it to the numpy array. Also, use relative imports in tests. Finally, fix some print-function bugs in the 'bin' and 'batchexamples' folder and rerun the python notebooks, so the output reflects the changes made. --- bin/Notebooks/PyRadiomics Example.ipynb | 255 ++--- bin/Notebooks/Python3Notebook.ipynb | 227 ++-- bin/Notebooks/helloFeatureClass.ipynb | 979 +++++++++--------- bin/Notebooks/helloRadiomics.ipynb | 36 +- bin/addClassToBaseline.py | 16 +- bin/batchExamples/DatasetHierarchyReader.py | 14 +- .../GenerateInputCSV_Datasethierarchy.py | 2 +- bin/batchExamples/batchprocessing.py | 8 +- bin/helloFeatureClass.py | 4 +- bin/helloRadiomics.py | 14 +- radiomics/shape.py | 2 +- tests/test_docstrings.py | 2 +- tests/test_features.py | 2 +- 13 files changed, 719 insertions(+), 842 deletions(-) diff --git a/bin/Notebooks/PyRadiomics Example.ipynb b/bin/Notebooks/PyRadiomics Example.ipynb index 2b76bf1c..46d1b66d 100644 --- a/bin/Notebooks/PyRadiomics Example.ipynb +++ b/bin/Notebooks/PyRadiomics Example.ipynb @@ -55,9 +55,9 @@ "name": "stdout", "output_type": "stream", "text": [ - "dataDir, relative path: /Users/mader/Dropbox/Informatics/pyradiomics/bin/Notebooks/../../data\n", - "dataDir, absolute path: /Users/mader/Dropbox/Informatics/pyradiomics/data\n", - "Parameter file, absolute path: /Users/mader/Dropbox/Informatics/pyradiomics/bin/Params.yaml\n" + "dataDir, relative path: E:\\Git-Repos\\4Quant\\pyradiomics\\bin\\Notebooks\\..\\..\\data\n", + "dataDir, absolute path: E:\\Git-Repos\\4Quant\\pyradiomics\\data\n", + "Parameter file, absolute path: E:\\Git-Repos\\4Quant\\pyradiomics\\bin\\Params.yaml\n" ] } ], @@ -122,11 +122,11 @@ "output_type": "stream", "text": [ "Extraction parameters:\n", - "\t {'resampledPixelSpacing': None, 'interpolator': 3, 'label': 1, 'verbose': False, 'padDistance': 5}\n", + "\t {'label': 1, 'interpolator': 3, 'padDistance': 5, 'verbose': False, 'resampledPixelSpacing': None}\n", "Enabled filters:\n", "\t {'Original': {}}\n", "Enabled features:\n", - "\t {'glcm': [], 'glrlm': [], 'glszm': [], 'shape': [], 'firstorder': []}\n" + "\t {'shape': [], 'firstorder': [], 'glrlm': [], 'glszm': [], 'glcm': []}\n" ] } ], @@ -158,11 +158,11 @@ "output_type": "stream", "text": [ "Extraction parameters:\n", - "\t {'verbose': True, 'sigma': [1, 2, 3], 'binWidth': 20, 'resampledPixelSpacing': None, 'interpolator': 3, 'padDistance': 5, 'label': 1}\n", + "\t {'binWidth': 20, 'verbose': True, 'sigma': [1, 2, 3], 'label': 1, 'interpolator': 3, 'padDistance': 5, 'resampledPixelSpacing': None}\n", "Enabled filters:\n", "\t {'Original': {}}\n", "Enabled features:\n", - "\t {'glcm': [], 'glrlm': [], 'glszm': [], 'shape': [], 'firstorder': []}\n" + "\t {'shape': [], 'firstorder': [], 'glrlm': [], 'glszm': [], 'glcm': []}\n" ] } ], @@ -193,11 +193,11 @@ "output_type": "stream", "text": [ "Extraction parameters:\n", - "\t {'verbose': True, 'sigma': [1, 2, 3], 'binWidth': 20, 'resampledPixelSpacing': None, 'interpolator': 3, 'padDistance': 5, 'label': 1}\n", + "\t {'binWidth': 20, 'verbose': True, 'sigma': [1, 2, 3], 'label': 1, 'interpolator': 3, 'padDistance': 5, 'resampledPixelSpacing': None}\n", "Enabled filters:\n", "\t {'Original': {}}\n", "Enabled features:\n", - "\t {'glcm': [], 'glrlm': [], 'glszm': [], 'shape': [], 'firstorder': []}\n" + "\t {'shape': [], 'firstorder': [], 'glrlm': [], 'glszm': [], 'glcm': []}\n" ] } ], @@ -229,7 +229,7 @@ "\t {'firstorder': []}\n", "\n", "Enabled features:\n", - "\t {'glcm': ['Autocorrelation', 'Homogeneity1', 'SumSquares'], 'firstorder': []}\n" + "\t {'firstorder': [], 'glcm': ['Autocorrelation', 'Homogeneity1', 'SumSquares']}\n" ] } ], @@ -270,11 +270,11 @@ "output_type": "stream", "text": [ "Extraction parameters:\n", - "\t {'verbose': True, 'binWidth': 25, 'resampledPixelSpacing': None, 'weightingNorm': None, 'interpolator': 'sitkBSpline', 'padDistance': 5, 'label': 1}\n", + "\t {'binWidth': 25, 'verbose': True, 'weightingNorm': None, 'label': 1, 'interpolator': 'sitkBSpline', 'padDistance': 5, 'resampledPixelSpacing': None}\n", "Enabled filters:\n", "\t {'Original': {}}\n", "Enabled features:\n", - "\t {'glcm': None, 'glrlm': None, 'glszm': None, 'shape': None, 'firstorder': []}\n" + "\t {'shape': None, 'firstorder': [], 'glrlm': None, 'glszm': None, 'glcm': None}\n" ] } ], @@ -310,103 +310,46 @@ "collapsed": false }, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "FAILED: Traceback (most recent call last):\n", - " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/base.py\", line 73, in calculateFeatures\n", - " self.featureValues[feature] = eval(call)\n", - " File \"\", line 1, in \n", - " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/shape.py\", line 228, in getMaximum2DDiameterColumnFeatureValue\n", - " return self._getMaximum2Ddiameter(1)\n", - " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/shape.py\", line 126, in _getMaximum2Ddiameter\n", - " for i in numpy.unique(a[:, dim]):\n", - "IndexError: too many indices for array\n", - "\n", - "FAILED: Traceback (most recent call last):\n", - " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/base.py\", line 73, in calculateFeatures\n", - " self.featureValues[feature] = eval(call)\n", - " File \"\", line 1, in \n", - " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/shape.py\", line 221, in getMaximum2DDiameterSliceFeatureValue\n", - " return self._getMaximum2Ddiameter(0)\n", - " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/shape.py\", line 126, in _getMaximum2Ddiameter\n", - " for i in numpy.unique(a[:, dim]):\n", - "IndexError: too many indices for array\n", - "\n", - "FAILED: Traceback (most recent call last):\n", - " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/base.py\", line 73, in calculateFeatures\n", - " self.featureValues[feature] = eval(call)\n", - " File \"\", line 1, in \n", - " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/shape.py\", line 235, in getMaximum2DDiameterRowFeatureValue\n", - " return self._getMaximum2Ddiameter(2)\n", - " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/shape.py\", line 126, in _getMaximum2Ddiameter\n", - " for i in numpy.unique(a[:, dim]):\n", - "IndexError: too many indices for array\n", - "\n", - "calculate GLCM: 24%|██▍ | 8/33 [00:00<00:00, 73.74it/s]" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\t\tComputing shape\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "calculate GLCM: 100%|██████████| 33/33 [00:01<00:00, 32.69it/s]\n" - ] - }, { "name": "stdout", "output_type": "stream", "text": [ - "\t\tComputing glcm\n" + "\t\tComputing shape\n", + "\t\tComputing firstorder\n", + "\t\tComputing glrlm\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "calculate GLSZM: 27%|██▋ | 9/33 [00:00<00:00, 89.69it/s]" + "calculate GLSZM: 100%|█████████████████████████████████████████████████████████████████| 33/33 [00:00<00:00, 81.68it/s]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "\t\tComputing glrlm\n" + "\t\tComputing glszm\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "calculate GLSZM: 100%|██████████| 33/33 [00:00<00:00, 72.79it/s]" + "calculate GLCM: 100%|██████████████████████████████████████████████████████████████████| 33/33 [00:00<00:00, 51.00it/s]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "\t\tComputing glszm\n", - "\t\tComputing firstorder\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\n" + "\t\tComputing glcm\n" ] } ], "source": [ - "result = extractor.execute(imagePath, labelPath)" + "result = extractor.execute(os.path.abspath(imagePath), os.path.abspath(labelPath))" ] }, { @@ -425,107 +368,107 @@ "\n", "Calculated features\n", "\t general_info_BoundingBox : (162; 84; 11; 47; 70; 7)\n", - "\t general_info_GeneralSettings : {'verbose': True; 'binWidth': 25; 'resampledPixelSpacing': None; 'weightingNorm': None; 'interpolator': 'sitkBSpline'; 'padDistance': 5; 'label': 1}\n", + "\t general_info_GeneralSettings : {'binWidth': 25; 'verbose': True; 'weightingNorm': None; 'label': 1; 'interpolator': 'sitkBSpline'; 'padDistance': 5; 'resampledPixelSpacing': None}\n", "\t general_info_ImageHash : 5c9ce3ca174f0f8324aa4d277e0fef82dc5ac566\n", "\t general_info_ImageSpacing : (0.7812499999999999; 0.7812499999999999; 6.499999999999998)\n", "\t general_info_InputImages : {'Original': {}}\n", "\t general_info_MaskHash : 9dc2c3137b31fd872997d92c9a92d5178126d9d3\n", - "\t general_info_Version : v1.0.1.post5.dev0+g72ac3cb\n", + "\t general_info_Version : v1.0.1.post6.dev0+g5b1e8bb\n", "\t general_info_VolumeNum : 2\n", "\t general_info_VoxelNum : 4137\n", "\t original_shape_SurfaceArea : 6438.82160378\n", - "\t original_shape_Sphericity : 0.485061744222\n", - "\t original_shape_Maximum2DDiameterColumn : nan\n", - "\t original_shape_Roundness : 0.6146906661500379\n", - "\t original_shape_Compactness1 : 26.7546787215\n", - "\t original_shape_SurfaceVolumeRatio : 0.392308261863\n", - "\t original_shape_Maximum2DDiameterSlice : nan\n", + "\t original_shape_Maximum2DDiameterSlice : 47.2187913633\n", + "\t original_shape_Maximum2DDiameterRow : 61.5801767135\n", + "\t original_shape_Volume : 16412.65869140624\n", "\t original_shape_Maximum3DDiameter : 65.53661458728622\n", - "\t original_shape_Maximum2DDiameterRow : nan\n", + "\t original_shape_Elongation : 1.7789885567018646\n", "\t original_shape_Flatness : 1.2191850589688844\n", + "\t original_shape_Maximum2DDiameterColumn : 44.5487904052\n", "\t original_shape_SphericalDisproportion : 2.06159321347\n", - "\t original_shape_Volume : 16412.65869140624\n", - "\t original_shape_Elongation : 1.7789885567018646\n", + "\t original_shape_Roundness : 0.6146906661500379\n", + "\t original_shape_Compactness1 : 26.7546787215\n", + "\t original_shape_Sphericity : 0.485061744222\n", "\t original_shape_Compactness2 : 0.114127701901\n", - "\t original_glcm_Homogeneity2 : 0.189156155892\n", - "\t original_glcm_SumVariance : 895.891808819\n", - "\t original_glcm_DifferenceAverage : 5.58932678922\n", - "\t original_glcm_ClusterProminence : 26251.1709801\n", - "\t original_glcm_DifferenceEntropy : 3.79686113536\n", - "\t original_glcm_Autocorrelation : 292.684050471\n", - "\t original_glcm_SumSquares : 39.9781084143\n", - "\t original_glcm_Dissimilarity : 5.58932678922\n", - "\t original_glcm_SumVariance2 : 103.142793792\n", - "\t original_glcm_ClusterShade : -52.9707943386\n", - "\t original_glcm_ClusterTendency : 103.142793792\n", - "\t original_glcm_Imc2 : 0.692033706271\n", - "\t original_glcm_SumEntropy : 5.31547876648\n", - "\t original_glcm_Imc1 : -0.091940840043\n", - "\t original_glcm_Energy : 0.00290880217681\n", - "\t original_glcm_Correlation : 0.335214788202\n", - "\t original_glcm_Idn : 0.866370546902\n", - "\t original_glcm_Homogeneity1 : 0.276140402104\n", - "\t original_glcm_Entropy : 8.79428086119\n", - "\t original_glcm_DifferenceVariance : 17.6107741076\n", - "\t original_glcm_Idm : 0.189156155892\n", - "\t original_glcm_SumAverage : 33.4497492152\n", - "\t original_glcm_AverageIntensity : 17.1242601309\n", - "\t original_glcm_Id : 0.276140402104\n", - "\t original_glcm_MaximumProbability : 0.00792784235012\n", - "\t original_glcm_InverseVariance : 0.188666637795\n", - "\t original_glcm_Contrast : 52.2310659277\n", - "\t original_glcm_Idmn : 0.957796447609\n", - "\t original_glrlm_LongRunHighGrayLevelEmphasis : 341.908225705\n", - "\t original_glrlm_ShortRunEmphasis : 0.955813827306\n", + "\t original_shape_SurfaceVolumeRatio : 0.392308261863\n", + "\t original_firstorder_Minimum : 468.0\n", + "\t original_firstorder_Maximum : 1266.0\n", + "\t original_firstorder_Median : 812.0\n", + "\t original_firstorder_10Percentile : 632.0\n", + "\t original_firstorder_RobustMeanAbsoluteDeviation : 103.00138343\n", + "\t original_firstorder_StandardDeviation : 156.611235894\n", + "\t original_firstorder_InterquartileRange : 253.0\n", + "\t original_firstorder_Range : 798.0\n", + "\t original_firstorder_MeanAbsoluteDeviation : 133.447261953\n", + "\t original_firstorder_90Percentile : 1044.4\n", + "\t original_firstorder_Uniformity : 0.0451569635559\n", + "\t original_firstorder_Kurtosis : 2.18077293939\n", + "\t original_firstorder_Entropy : 4.6019355539\n", + "\t original_firstorder_Skewness : 0.275650859086\n", + "\t original_firstorder_Variance : 24527.0792084\n", + "\t original_firstorder_RootMeanSquared : 2829.57282108\n", + "\t original_firstorder_TotalEnergy : 131407662126.0\n", + "\t original_firstorder_Mean : 825.235436307\n", + "\t original_firstorder_Energy : 33122817481.0\n", "\t original_glrlm_LongRunLowGrayLevelEmphasis : 0.0104694333711\n", - "\t original_glrlm_LowGrayLevelRunEmphasis : 0.00846567390082\n", + "\t original_glrlm_ShortRunLowGrayLevelEmphasis : 0.0080944625119\n", + "\t original_glrlm_ShortRunHighGrayLevelEmphasis : 269.366654415\n", + "\t original_glrlm_LongRunEmphasis : 1.22741432468\n", + "\t original_glrlm_LongRunHighGrayLevelEmphasis : 341.908225705\n", "\t original_glrlm_GrayLevelNonUniformityNormalized : 0.0451916226163\n", - "\t original_glrlm_RunVariance : 0.0849939088453\n", - "\t original_glrlm_RunEntropy : 4.91343459806\n", + "\t original_glrlm_RunLengthNonUniformity : 3473.88954354\n", "\t original_glrlm_RunLengthNonUniformityNormalized : 0.894736783551\n", - "\t original_glrlm_LongRunEmphasis : 1.22741432468\n", - "\t original_glrlm_GrayLevelNonUniformity : 174.640108304\n", + "\t original_glrlm_RunEntropy : 4.91343459806\n", "\t original_glrlm_RunPercentage : 0.934010152284\n", + "\t original_glrlm_GrayLevelNonUniformity : 174.640108304\n", + "\t original_glrlm_ShortRunEmphasis : 0.955813827306\n", "\t original_glrlm_GrayLevelVariance : 39.074009627\n", + "\t original_glrlm_RunVariance : 0.0849939088453\n", "\t original_glrlm_HighGrayLevelRunEmphasis : 281.50156957\n", - "\t original_glrlm_RunLengthNonUniformity : 3473.88954354\n", - "\t original_glrlm_ShortRunLowGrayLevelEmphasis : 0.0080944625119\n", - "\t original_glrlm_ShortRunHighGrayLevelEmphasis : 269.366654415\n", - "\t original_glszm_ZoneEntropy : 6.5082149862\n", - "\t original_glszm_HighIntensitySmallAreaEmphasis : 193.438051926\n", + "\t original_glrlm_LowGrayLevelRunEmphasis : 0.00846567390082\n", "\t original_glszm_HighIntensityLargeAreaEmphasis : 3514.76149733\n", - "\t original_glszm_LowIntensityEmphasis : 0.00910094202771\n", - "\t original_glszm_IntensityVariability : 82.3871657754\n", + "\t original_glszm_LowIntensityLargeAreaEmphasis : 0.127238415533\n", "\t original_glszm_LargeAreaEmphasis : 13.6155080214\n", - "\t original_glszm_GrayLevelVariance : 40.6031399239\n", - "\t original_glszm_ZoneVariance : 8.72123909749\n", - "\t original_glszm_HighIntensityEmphasis : 288.623529412\n", - "\t original_glszm_SizeZoneVariability : 747.596791444\n", + "\t original_glszm_SizeZoneVariabilityNormalized : 0.399784380451\n", "\t original_glszm_LowIntensitySmallAreaEmphasis : 0.0064169820551\n", + "\t original_glszm_IntensityVariability : 82.3871657754\n", + "\t original_glszm_ZoneEntropy : 6.5082149862\n", + "\t original_glszm_HighIntensityEmphasis : 288.623529412\n", + "\t original_glszm_GrayLevelVariance : 40.6031399239\n", "\t original_glszm_IntensityVariabilityNormalized : 0.0440573079013\n", + "\t original_glszm_SizeZoneVariability : 747.596791444\n", "\t original_glszm_ZonePercentage : 0.4520183708\n", + "\t original_glszm_ZoneVariance : 8.72123909749\n", + "\t original_glszm_LowIntensityEmphasis : 0.00910094202771\n", + "\t original_glszm_HighIntensitySmallAreaEmphasis : 193.438051926\n", "\t original_glszm_SmallAreaEmphasis : 0.656447899959\n", - "\t original_glszm_LowIntensityLargeAreaEmphasis : 0.127238415533\n", - "\t original_glszm_SizeZoneVariabilityNormalized : 0.399784380451\n", - "\t original_firstorder_Minimum : 468.0\n", - "\t original_firstorder_RobustMeanAbsoluteDeviation : 103.00138343\n", - "\t original_firstorder_Energy : 33122817481.0\n", - "\t original_firstorder_RootMeanSquared : 2829.57282108\n", - "\t original_firstorder_Mean : 825.235436307\n", - "\t original_firstorder_Maximum : 1266.0\n", - "\t original_firstorder_10Percentile : 632.0\n", - "\t original_firstorder_Entropy : 4.6019355539\n", - "\t original_firstorder_TotalEnergy : 131407662126.0\n", - "\t original_firstorder_MeanAbsoluteDeviation : 133.447261953\n", - "\t original_firstorder_Median : 812.0\n", - "\t original_firstorder_Range : 798.0\n", - "\t original_firstorder_StandardDeviation : 156.611235894\n", - "\t original_firstorder_Skewness : 0.275650859086\n", - "\t original_firstorder_Uniformity : 0.0451569635559\n", - "\t original_firstorder_Variance : 24527.0792084\n", - "\t original_firstorder_InterquartileRange : 253.0\n", - "\t original_firstorder_90Percentile : 1044.4\n", - "\t original_firstorder_Kurtosis : 2.18077293939\n" + "\t original_glcm_Imc2 : 0.692033706271\n", + "\t original_glcm_MaximumProbability : 0.00792784235012\n", + "\t original_glcm_Autocorrelation : 292.684050471\n", + "\t original_glcm_ClusterTendency : 103.142793792\n", + "\t original_glcm_Idn : 0.866370546902\n", + "\t original_glcm_DifferenceEntropy : 3.79686113536\n", + "\t original_glcm_SumSquares : 39.9781084143\n", + "\t original_glcm_SumEntropy : 5.31547876648\n", + "\t original_glcm_DifferenceAverage : 5.58932678922\n", + "\t original_glcm_SumAverage : 33.4497492152\n", + "\t original_glcm_Energy : 0.00290880217681\n", + "\t original_glcm_ClusterShade : -52.9707943386\n", + "\t original_glcm_Entropy : 8.79428086119\n", + "\t original_glcm_Homogeneity1 : 0.276140402104\n", + "\t original_glcm_SumVariance2 : 103.142793792\n", + "\t original_glcm_Contrast : 52.2310659277\n", + "\t original_glcm_Dissimilarity : 5.58932678922\n", + "\t original_glcm_InverseVariance : 0.188666637795\n", + "\t original_glcm_DifferenceVariance : 17.6107741076\n", + "\t original_glcm_Idmn : 0.957796447609\n", + "\t original_glcm_Id : 0.276140402104\n", + "\t original_glcm_Imc1 : -0.091940840043\n", + "\t original_glcm_Idm : 0.189156155892\n", + "\t original_glcm_ClusterProminence : 26251.1709801\n", + "\t original_glcm_Homogeneity2 : 0.189156155892\n", + "\t original_glcm_AverageIntensity : 17.1242601309\n", + "\t original_glcm_Correlation : 0.335214788202\n", + "\t original_glcm_SumVariance : 895.891808819\n" ] } ], @@ -541,7 +484,7 @@ "metadata": { "anaconda-cloud": {}, "kernelspec": { - "display_name": "Python [default]", + "display_name": "Python 3", "language": "python", "name": "python3" }, diff --git a/bin/Notebooks/Python3Notebook.ipynb b/bin/Notebooks/Python3Notebook.ipynb index 958f358e..c7e3823f 100644 --- a/bin/Notebooks/Python3Notebook.ipynb +++ b/bin/Notebooks/Python3Notebook.ipynb @@ -59,7 +59,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 4, @@ -68,9 +68,9 @@ }, { "data": { - "image/png": "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\n", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAeQAAADtCAYAAABu1gaFAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAEyFJREFUeJzt3V+s5GV5wPHvc85ZXOSPgLtsN0C7VkksMXVNNgSjFxRj\nQ40JmBoiTQ0XpOuFJpp4Q7jBmppoUqVeGJO1bNgmViT+KaQhbQkhQW+oZ5X6h62pEoiQ/YfsCiiy\nu2eeXswPe9zumTMz5/d75z2/+X6SzZn5nZnzPu+cec6zv5nnnTcyE0mSNFsLsw5AkiRZkCVJqoIF\nWZKkCliQJUmqgAVZkqQKWJAlSaqABVmSpApYkCVJqoAFWZKkCixt5M4RcSPwRWAR+MfM/Oyo22/b\nti137dr1/44fPHhwI2FIffR8Zm4vOeAk+bw1FvOijf35WD+eTn96WSXm0qvHq0eTOZKnxs7lqTMq\nIhaBLwHvBZ4FvhcRD2bmk2vdZ9euXSwvL5/rZ00bhtRXz5QcbNJ8vogl/pKdncZU6uW7xQJ/fhYL\n/I0rMY/hOM5lEp859dTYubyR5/y1wM8y86nMPAXcB9y0gZ8naXbMZ2nGNlKQrwB+ser6s82x3xMR\neyNiOSKWjx8/voHhJHVo3Xxencu/ZaVocNI86PxVoczcl5l7MnPP9u1F3xKT1KLVubyVxVmHI/XO\nRgryc8BVq65f2RyTtPmYz9KMbaRN8nvA1RHxJoaJ+yHgr0bd4eDBg+ds4Bq1J7MNX1IRE+XzloAd\n53V7llyi4WY4TokxbISabIzOh2jGKTDQqfFvOnVBzswzEfEx4N8ZLpPYn5k/mfbnSZod81mavQ0t\nJMzMh4CHWopF0gyZz9Js+UldkiRVwIIsSVIFLMiSJFXAgixJUgW6/XT4MY1a2rTWkiiXQ0mzs2Uh\n+IOt3f75KLXsqcRZSV+WVg3HKTFGf+YyCc+QJUmqgAVZkqQKWJAlSaqABVmSpApYkCVJqkAVXdaj\nrNVNbfe1NDtbItjxuq67rDv98b+zsND9QAuL3Z/7RKEHLHryeEGhx+z4+Df1DFmSpApYkCVJqoAF\nWZKkCliQJUmqgAVZkqQKVN9lvZZJu69H3UfSZBaWFrh42/mdjlGqa7hIB3SBzuRePV7F5lJgnJ+O\nf1PPkCVJqoAFWZKkCliQJUmqgAVZkqQKWJAlSaqABVmSpApsaNlTRDwNvASsAGcyc08bQW3EqKVN\nbkghrW2SfF5cWuCCyy/oNh6X8UykyBIeyswlFsqcK5Z6zMbVxjrkP8vM51v4OZJmz3yWZsSXrCVJ\nqsBGC3IC/xERByNi77luEBF7I2I5IpY3OJakbo3M59W5fOL06RmEJ/XbRl+yfndmPhcRlwMPR8R/\nZ+Zjq2+QmfuAfQARsfbnWkqatZH5vDqX/+Sii8xlqWUbOkPOzOear8eAbwPXthGUpPLMZ2m2pj5D\njogLgIXMfKm5/OfAp1uLrAOTbkhh97XmxaT5vLBlgQt2dNtl3aeu4TIbWJRpCYoiXemF5lLoMRvX\nRl6y3gF8uylaS8A/Z+a/tRKVpNLMZ2nGpi7ImfkU8PYWY5E0I+azNHt1na9LkjSnLMiSJFXAgixJ\nUgXa+OjMTW/S7utR95HmwcKWRV5/+cXdjtGjTttedSb3qGO81HNsXHVFI0nSnLIgS5JUAQuyJEkV\nsCBLklQBC7IkSRWwIEuSVAGXPY0wammTG1Joni0sLfH6yy/tdAw3S5jMgo9XteOMq65oJEmaUxZk\nSZIqYEGWJKkCFmRJkipgQZYkqQJ2WU9p0g0p7L5WnywsLXL+9ks6HaNUB2yJDQb6soHFcJzF7gdZ\nKDAGQKHO9HHVFY0kSXPKgixJUgUsyJIkVcCCLElSBSzIkiRVYN0u64jYD7wfOJaZb2uOXQZ8HdgF\nPA3ckpknugtz85i0+3rUfaS2tZXPsbTE67a9sdtge9RpGyXmUujxKvIZ4yU6uaHcc2xM4zyy9wI3\nnnXsDuCRzLwaeKS5Lql+92I+S1VatyBn5mPAC2cdvgk40Fw+ANzcclySOmA+S/Wa9rWHHZl5uLl8\nBNix1g0jYm9ELEfE8pRjSerWWPm8Opeff/HlctFJc2LDbwbk8M3RNd8gzcx9mbknM/dsdCxJ3RqV\nz6tzedvFFxaOTOq/aQvy0YjYCdB8PdZeSJIKM5+lCkxbkB8Ebmsu3wY80E44kmbAfJYqMM6yp68B\n1wPbIuJZ4C7gs8D9EXE78AxwS5dB9sGopU1uSKFS2srnWFpi8dLLuwy13Af/F1j6UmbZU48erzld\n9rRuQc7MW9f41ntajkVSx8xnqV5+UpckSRWwIEuSVAELsiRJFbAgS5JUgXWbutS9STeksPtaM7e4\nxMKl2zsdokhnMpTptO3LBhbQqy7rrOxvqWfIkiRVwIIsSVIFLMiSJFXAgixJUgUsyJIkVcAu64pN\n2n096j5Sm2JxiYU3bOt4kELnCwXGyZ6MAfTm8RqOU9ffS8+QJUmqgAVZkqQKWJAlSaqABVmSpApY\nkCVJqoAFWZKkCrjsaRMatbTJDSlUQi4sMtj6hm4HKbAhA9CfZTw9WvbUq7lMoK5oJEmaUxZkSZIq\nYEGWJKkCFmRJkipgQZYkqQLrdllHxH7g/cCxzHxbc+xTwN8Ax5ub3ZmZD3UVpMY36YYUdl/Pl9by\neWGRwfkdd1n3qdO2QMd4nzaX6NXvfgLjRHMvcOM5jt+dmbubfxZjaXO4F/NZqtK6BTkzHwNeKBCL\npI6Zz1K9NnK+/rGI+GFE7I+IS9e6UUTsjYjliFjewFiSurVuPq/O5ePPW9Oltk1bkL8MvBnYDRwG\nPr/WDTNzX2buycw9U44lqVtj5fPqXN6+7bKS8UlzYaqCnJlHM3MlMwfAV4Br2w1LUinms1SHqT7L\nOiJ2Zubh5uoHgB+3F5K6MGn39aj7qF+myeeMRQZbL+40rsHaT81WlRimxFxG5XKbisxl0P0YAINS\nA41pnGVPXwOuB7ZFxLPAXcD1EbGb4XP5aeAjHcYoqSXms1SvdQtyZt56jsP3dBCLpI6Zz1K96loV\nLUnSnLIgS5JUAQuyJEkVsCBLklSBqZY9qT9GLW1yQwqtZZDw8ulul4wUW/ZUYJxBgUEKPVyFlnB1\nPwbAoNijNh7PkCVJqoAFWZKkCliQJUmqgAVZkqQKWJAlSaqAXdZakxtSaC0rCS+f6kuXdfcDldjC\noFhncoku60Ldz6WeY+PyDFmSpApYkCVJqoAFWZKkCliQJUmqgAVZkqQKWJAlSaqAy540MTek0CCz\n82VPpVakrBRY+1Jic4mVQuueBgXWcBWbS6m1YmPyDFmSpApYkCVJqoAFWZKkCliQJUmqgAVZkqQK\nrNtlHRFXAf8E7GDY+LgvM78YEZcBXwd2AU8Dt2Tmie5C1WYw6YYUdl+X1VY+nxkkv3zldKexDgp9\n8n+Jjt4yXdadDwGU+b2U67IuMszYxjlDPgN8MjOvAa4DPhoR1wB3AI9k5tXAI811SXUzn6VKrVuQ\nM/NwZn6/ufwScAi4ArgJONDc7ABwc1dBSmqH+SzVa6L3kCNiF/AO4HFgR2Yebr51hOFLYOe6z96I\nWI6I5Q3EKallk+bz6lz+1Qu/LBanNC/GLsgRcSHwTeATmfni6u/l8A3Cc74an5n7MnNPZu7ZUKSS\nWjNNPq/O5Tdc9sZCkUrzY6yCHBFbGCbvVzPzW83hoxGxs/n+TuBYNyFKapP5LNVpnC7rAO4BDmXm\nF1Z960HgNuCzzdcHOolQvTBp9/Wo+2h6beXzmUHy/G9OdRYnlOuyLjFMXzq5odRnf3c+BFCum3tc\n42wu8S7gw8CPIuKJ5tidDBP3/oi4HXgGuKWbECW1yHyWKrVuQc7M7wJrnaq8p91wJHXJfJbq5Sd1\nSZJUAQuyJEkVsCBLklQBC7IkSRUYp8ta6syopU1uSFGvM4Pklx0ve1oZdPrjf6fMxg8Fxii1GUeJ\nzSV6NJdJeIYsSVIFLMiSJFXAgixJUgUsyJIkVcCCLElSBeyyVrUm3ZDC7utyTq8MOPLiq52O0adO\n2zJjlGlL78vjVXKccXmGLElSBSzIkiRVwIIsSVIFLMiSJFXAgixJUgXsstamM2n39aj7aDpnVgYc\nOflKp2OU6oA905Ou4T51JvdpLpPwDFmSpApYkCVJqoAFWZKkCliQJUmqgAVZkqQKrFuQI+KqiHg0\nIp6MiJ9ExMeb45+KiOci4onm3/u6D1fStMxlqW7jLHs6A3wyM78fERcBByPi4eZ7d2fm33cXnjS+\nUUub3JACaDGXT60kh0/+tpMgX9OnpS9Fxhix7K9NgwJzyUK/+1LjjGvdgpyZh4HDzeWXIuIQcEXX\ngUlql7ks1W2i95AjYhfwDuDx5tDHIuKHEbE/Ii5tOTZJHTGXpfqMXZAj4kLgm8AnMvNF4MvAm4Hd\nDP/X/fk17rc3IpYjYrmFeCVtUBu5fOqlk8XilebFWAU5IrYwTOCvZua3ADLzaGauZOYA+Apw7bnu\nm5n7MnNPZu5pK2hJ02krl8+76JJyQUtzYpwu6wDuAQ5l5hdWHd+56mYfAH7cfniS2mIuS3Ubp8v6\nXcCHgR9FxBPNsTuBWyNiN5DA08BHOolQasGkG1L0tPu6tVxeWRnwwq+67bIetVlIq+MU6LTtVWdy\ngd9LiccLIAdFhhnbOF3W3wXO9dfpofbDkdQVc1mqm5/UJUlSBSzIkiRVwIIsSVIFLMiSJFVgnC5r\nqbcm7b4edZ95MlhJfvPiq92O0aMu6750ckOZLutSHeOlHrNxeYYsSVIFLMiSJFXAgixJUgUsyJIk\nVcCCLElSBSzIkiRVwGVP0jmMWto0ZxtSnNNgZcCvX+x4c4lCH/xfYnlVX5ZWQamNMsr88nOwUmSc\ncXmGLElSBSzIkiRVwIIsSVIFLMiSJFXAgixJUgXsspYmNOmGFH3svh6sDPjNr17udIxSHbAlxhkU\nGKNPj1exLusVu6wlSdJZLMiSJFXAgixJUgUsyJIkVcCCLElSBdbtso6IrcBjwOua238jM++KiDcB\n9wFvBA4CH87MU10GK9Vs0u7rUffpSlv5PDhzmldOHO001n51DfdjDOhZx/gm7LJ+FbghM98O7AZu\njIjrgM8Bd2fmW4ATwO3dhSmpJeazVKl1C3IOvbbgcEvzL4EbgG80xw8AN3cSoaTWmM9SvcZ6Dzki\nFiPiCeAY8DDwc+BkZp5pbvIscMUa990bEcsRsdxGwJI2Ztp8Xp3Lg1O/LhewNCfGKsiZuZKZu4Er\ngWuBt447QGbuy8w9mblnyhgltWjafF6dywvnXdBpjNI8mqjLOjNPAo8C7wQuiYjXmsKuBJ5rOTZJ\nHTKfpbqsW5AjYntEXNJcPh94L3CIYSJ/sLnZbcADXQUpqR3ms1SvcTaX2AkciIhFhgX8/sz814h4\nErgvIv4O+AFwT4dxSpvWqKVNM9iQopV8Hqyc5pUTR7qKEXDZU41jlBqn3FzKbGIxrnULcmb+EHjH\nOY4/xfD9J0mbhPks1ctP6pIkqQIWZEmSKmBBliSpAhZkSZIqEKM++L71wSKOA880V7cBzxcbvD7z\nPH/nvr4/ysztXQczrbNyGfydOvf5NM78x87logX59waOWJ7nT++a5/k79/7Nva/zGodzn8+5Q/vz\n9yVrSZIqYEGWJKkCsyzI+2Y4dg3mef7OvX/6Oq9xOPf51er8Z/YesiRJ+j++ZC1JUgUsyJIkVWAm\nBTkiboyIn0bEzyLijlnEUEpE7I+IYxHx41XHLouIhyPif5qvl84yxq5ExFUR8WhEPBkRP4mIjzfH\n52X+WyPiPyPiv5r5/21z/E0R8Xjz/P96RJw361inNU+5DObzvOZzqVwuXpCbbd++BPwFcA1wa0Rc\nUzqOgu4Fbjzr2B3AI5l5NfBIc72PzgCfzMxrgOuAjza/63mZ/6vADZn5dmA3cGNEXAd8Drg7M98C\nnABun2GMU5vDXAbzeV7zuUguz+IM+VrgZ5n5VGaeAu4DbppBHEVk5mPAC2cdvgk40Fw+ANxcNKhC\nMvNwZn6/ufwScAi4gvmZf2bmy83VLc2/BG4AvtEc38zzn6tcBvN5XvO5VC7PoiBfAfxi1fVnm2Pz\nZEdmHm4uHwF2zDKYEiJiF8N9eB9njuYfEYsR8QRwDHgY+DlwMjPPNDfZzM9/c3lobp7Pr5nHfC6R\nyzZ1zVgO1531eu1ZRFwIfBP4RGa+uPp7fZ9/Zq5k5m7gSoZnlG+dcUjqUN+fzzC/+Vwil2dRkJ8D\nrlp1/crm2Dw5GhE7AZqvx2YcT2ciYgvD5P1qZn6rOTw3839NZp4EHgXeCVwSEUvNtzbz899cHpqb\n57P53G0uz6Igfw+4uulOOw/4EPDgDOKYpQeB25rLtwEPzDCWzkREAPcAhzLzC6u+NS/z3x4RlzSX\nzwfey/B9t0eBDzY328zzN5eH5uX5PLf5XCqXZ/JJXRHxPuAfgEVgf2Z+pngQhUTE14DrGW7TdRS4\nC/gX4H7gDxluYXdLZp7dKLLpRcS7ge8APwIGzeE7Gb7vNA/z/1OGjR6LDP/ze39mfjoi/phhA9Rl\nwA+Av87MV2cX6fTmKZfBfGZO87lULvvRmZIkVcCmLkmSKmBBliSpAhZkSZIqYEGWJKkCFmRJkipg\nQZYkqQIWZEmSKvC/TUjq9LvqvxIAAAAASUVORK5CYII=\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -123,44 +123,44 @@ " general_info_Version\n", " general_info_VolumeNum\n", " general_info_VoxelNum\n", - " original_firstorder_10Percentile\n", + " original_firstorder_Uniformity\n", " ...\n", - " original_firstorder_Median\n", - " original_firstorder_Minimum\n", - " original_firstorder_Range\n", - " original_firstorder_RobustMeanAbsoluteDeviation\n", + " original_firstorder_Variance\n", " original_firstorder_RootMeanSquared\n", + " original_firstorder_InterquartileRange\n", + " original_firstorder_MeanAbsoluteDeviation\n", + " original_firstorder_RobustMeanAbsoluteDeviation\n", + " original_firstorder_Energy\n", " original_firstorder_Skewness\n", + " original_firstorder_Maximum\n", " original_firstorder_StandardDeviation\n", " original_firstorder_TotalEnergy\n", - " original_firstorder_Uniformity\n", - " original_firstorder_Variance\n", " \n", " \n", " \n", " \n", " 0\n", " (0; 0; 0; 32; 32; 32)\n", - " {'interpolator': 3; 'verbose': True; 'label': ...\n", + " {'padDistance': 5; 'verbose': True; 'interpola...\n", " dd1063b4904affacbcfa769510e55d35690f6961\n", " (1.0; 1.0; 1.0)\n", " {'Original': {}}\n", - " d72fb2bdbaffacc0632f4f1a782fdbc10b9155e0\n", - " v1.0.1.post5.dev0+g72ac3cb\n", + " 1daf886d07071ceba6a23f52cdcb6460dc91c19a\n", + " v1.0.1.post6.dev0+g5b1e8bb\n", " 1\n", " 1024\n", - " 10.009766\n", + " 0.25\n", " ...\n", + " 833.435014\n", + " 2050.203267\n", " 50.0\n", - " 0.0\n", - " 100.0\n", + " 25.000763\n", " 19.97066\n", - " 2050.203267\n", + " 4.304213e+09\n", " 0.0\n", + " 100.0\n", " 28.869275\n", " 4.304213e+09\n", - " 0.25\n", - " 833.435014\n", " \n", " \n", "\n", @@ -169,34 +169,40 @@ ], "text/plain": [ " general_info_BoundingBox general_info_GeneralSettings \\\n", - "0 (0; 0; 0; 32; 32; 32) {'interpolator': 3; 'verbose': True; 'label': ... \n", + "0 (0; 0; 0; 32; 32; 32) {'padDistance': 5; 'verbose': True; 'interpola... \n", "\n", " general_info_ImageHash general_info_ImageSpacing \\\n", "0 dd1063b4904affacbcfa769510e55d35690f6961 (1.0; 1.0; 1.0) \n", "\n", " general_info_InputImages general_info_MaskHash \\\n", - "0 {'Original': {}} d72fb2bdbaffacc0632f4f1a782fdbc10b9155e0 \n", + "0 {'Original': {}} 1daf886d07071ceba6a23f52cdcb6460dc91c19a \n", "\n", " general_info_Version general_info_VolumeNum general_info_VoxelNum \\\n", - "0 v1.0.1.post5.dev0+g72ac3cb 1 1024 \n", + "0 v1.0.1.post6.dev0+g5b1e8bb 1 1024 \n", "\n", - " original_firstorder_10Percentile ... \\\n", - "0 10.009766 ... \n", + " original_firstorder_Uniformity ... \\\n", + "0 0.25 ... \n", "\n", - " original_firstorder_Median original_firstorder_Minimum \\\n", - "0 50.0 0.0 \n", + " original_firstorder_Variance original_firstorder_RootMeanSquared \\\n", + "0 833.435014 2050.203267 \n", "\n", - " original_firstorder_Range original_firstorder_RobustMeanAbsoluteDeviation \\\n", - "0 100.0 19.97066 \n", + " original_firstorder_InterquartileRange \\\n", + "0 50.0 \n", "\n", - " original_firstorder_RootMeanSquared original_firstorder_Skewness \\\n", - "0 2050.203267 0.0 \n", + " original_firstorder_MeanAbsoluteDeviation \\\n", + "0 25.000763 \n", "\n", - " original_firstorder_StandardDeviation original_firstorder_TotalEnergy \\\n", - "0 28.869275 4.304213e+09 \n", + " original_firstorder_RobustMeanAbsoluteDeviation \\\n", + "0 19.97066 \n", "\n", - " original_firstorder_Uniformity original_firstorder_Variance \n", - "0 0.25 833.435014 \n", + " original_firstorder_Energy original_firstorder_Skewness \\\n", + "0 4.304213e+09 0.0 \n", + "\n", + " original_firstorder_Maximum original_firstorder_StandardDeviation \\\n", + "0 100.0 28.869275 \n", + "\n", + " original_firstorder_TotalEnergy \n", + "0 4.304213e+09 \n", "\n", "[1 rows x 28 columns]" ] @@ -229,74 +235,41 @@ "collapsed": false }, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "FAILED: Traceback (most recent call last):\n", - " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/base.py\", line 73, in calculateFeatures\n", - " self.featureValues[feature] = eval(call)\n", - " File \"\", line 1, in \n", - " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/shape.py\", line 221, in getMaximum2DDiameterSliceFeatureValue\n", - " return self._getMaximum2Ddiameter(0)\n", - " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/shape.py\", line 126, in _getMaximum2Ddiameter\n", - " for i in numpy.unique(a[:, dim]):\n", - "IndexError: too many indices for array\n", - "\n", - "FAILED: Traceback (most recent call last):\n", - " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/base.py\", line 73, in calculateFeatures\n", - " self.featureValues[feature] = eval(call)\n", - " File \"\", line 1, in \n", - " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/shape.py\", line 235, in getMaximum2DDiameterRowFeatureValue\n", - " return self._getMaximum2Ddiameter(2)\n", - " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/shape.py\", line 126, in _getMaximum2Ddiameter\n", - " for i in numpy.unique(a[:, dim]):\n", - "IndexError: too many indices for array\n", - "\n", - "FAILED: Traceback (most recent call last):\n", - " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/base.py\", line 73, in calculateFeatures\n", - " self.featureValues[feature] = eval(call)\n", - " File \"\", line 1, in \n", - " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/shape.py\", line 228, in getMaximum2DDiameterColumnFeatureValue\n", - " return self._getMaximum2Ddiameter(1)\n", - " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/shape.py\", line 126, in _getMaximum2Ddiameter\n", - " for i in numpy.unique(a[:, dim]):\n", - "IndexError: too many indices for array\n", - "\n", - "calculate GLCM: 100%|██████████| 4/4 [00:00<00:00, 164.24it/s]\n", - "calculate GLSZM: 0%| | 0/4 [00:00general_info_Version\n", " general_info_VolumeNum\n", " general_info_VoxelNum\n", - " original_firstorder_10Percentile\n", - " ...\n", " original_shape_Maximum2DDiameterColumn\n", - " original_shape_Maximum2DDiameterRow\n", - " original_shape_Maximum2DDiameterSlice\n", - " original_shape_Maximum3DDiameter\n", - " original_shape_Roundness\n", - " original_shape_SphericalDisproportion\n", - " original_shape_Sphericity\n", - " original_shape_SurfaceArea\n", - " original_shape_SurfaceVolumeRatio\n", - " original_shape_Volume\n", + " ...\n", + " original_glrlm_HighGrayLevelRunEmphasis\n", + " original_glrlm_GrayLevelNonUniformity\n", + " original_glrlm_LongRunHighGrayLevelEmphasis\n", + " original_glrlm_LongRunEmphasis\n", + " original_glrlm_GrayLevelNonUniformityNormalized\n", + " original_glrlm_ShortRunLowGrayLevelEmphasis\n", + " original_glrlm_RunVariance\n", + " original_glrlm_RunPercentage\n", + " original_glrlm_ShortRunHighGrayLevelEmphasis\n", + " original_glrlm_ShortRunEmphasis\n", " \n", " \n", " \n", " \n", " 0\n", " (0; 0; 0; 32; 32; 32)\n", - " {'interpolator': 3; 'verbose': True; 'label': ...\n", + " {'padDistance': 5; 'verbose': True; 'interpola...\n", " dd1063b4904affacbcfa769510e55d35690f6961\n", " (1.0; 1.0; 1.0)\n", " {'Original': {}}\n", - " d72fb2bdbaffacc0632f4f1a782fdbc10b9155e0\n", - " v1.0.1.post5.dev0+g72ac3cb\n", + " 1daf886d07071ceba6a23f52cdcb6460dc91c19a\n", + " v1.0.1.post6.dev0+g5b1e8bb\n", " 1\n", " 1024\n", - " 10.009766\n", + " 31.0\n", " ...\n", - " NaN\n", - " NaN\n", - " NaN\n", - " 53.693575\n", - " 0.224041\n", - " 5.823731\n", - " 0.171711\n", - " 2861.225334\n", - " 2.794165\n", - " 1024.0\n", + " 7.497225\n", + " 28.953289\n", + " 2276.534562\n", + " 296.399351\n", + " 0.250258\n", + " 0.016999\n", + " 2.421762\n", + " 0.113037\n", + " 0.298798\n", + " 0.044432\n", " \n", " \n", "\n", @@ -362,37 +335,43 @@ ], "text/plain": [ " general_info_BoundingBox general_info_GeneralSettings \\\n", - "0 (0; 0; 0; 32; 32; 32) {'interpolator': 3; 'verbose': True; 'label': ... \n", + "0 (0; 0; 0; 32; 32; 32) {'padDistance': 5; 'verbose': True; 'interpola... \n", "\n", " general_info_ImageHash general_info_ImageSpacing \\\n", "0 dd1063b4904affacbcfa769510e55d35690f6961 (1.0; 1.0; 1.0) \n", "\n", " general_info_InputImages general_info_MaskHash \\\n", - "0 {'Original': {}} d72fb2bdbaffacc0632f4f1a782fdbc10b9155e0 \n", + "0 {'Original': {}} 1daf886d07071ceba6a23f52cdcb6460dc91c19a \n", "\n", " general_info_Version general_info_VolumeNum general_info_VoxelNum \\\n", - "0 v1.0.1.post5.dev0+g72ac3cb 1 1024 \n", + "0 v1.0.1.post6.dev0+g5b1e8bb 1 1024 \n", + "\n", + " original_shape_Maximum2DDiameterColumn ... \\\n", + "0 31.0 ... \n", "\n", - " original_firstorder_10Percentile ... \\\n", - "0 10.009766 ... \n", + " original_glrlm_HighGrayLevelRunEmphasis \\\n", + "0 7.497225 \n", "\n", - " original_shape_Maximum2DDiameterColumn \\\n", - "0 NaN \n", + " original_glrlm_GrayLevelNonUniformity \\\n", + "0 28.953289 \n", "\n", - " original_shape_Maximum2DDiameterRow original_shape_Maximum2DDiameterSlice \\\n", - "0 NaN NaN \n", + " original_glrlm_LongRunHighGrayLevelEmphasis \\\n", + "0 2276.534562 \n", "\n", - " original_shape_Maximum3DDiameter original_shape_Roundness \\\n", - "0 53.693575 0.224041 \n", + " original_glrlm_LongRunEmphasis \\\n", + "0 296.399351 \n", "\n", - " original_shape_SphericalDisproportion original_shape_Sphericity \\\n", - "0 5.823731 0.171711 \n", + " original_glrlm_GrayLevelNonUniformityNormalized \\\n", + "0 0.250258 \n", "\n", - " original_shape_SurfaceArea original_shape_SurfaceVolumeRatio \\\n", - "0 2861.225334 2.794165 \n", + " original_glrlm_ShortRunLowGrayLevelEmphasis original_glrlm_RunVariance \\\n", + "0 0.016999 2.421762 \n", "\n", - " original_shape_Volume \n", - "0 1024.0 \n", + " original_glrlm_RunPercentage original_glrlm_ShortRunHighGrayLevelEmphasis \\\n", + "0 0.113037 0.298798 \n", + "\n", + " original_glrlm_ShortRunEmphasis \n", + "0 0.044432 \n", "\n", "[1 rows x 102 columns]" ] @@ -421,9 +400,9 @@ "output_type": "stream", "text": [ "Calculating firstorder features\n", - "Calculating shape features\n", - "Calculating glszm features\n", "Calculating glcm features\n", + "Calculating glszm features\n", + "Calculating shape features\n", "Calculating glrlm features\n" ] } @@ -439,7 +418,7 @@ "metadata": { "anaconda-cloud": {}, "kernelspec": { - "display_name": "Python [default]", + "display_name": "Python 3", "language": "python", "name": "python3" }, diff --git a/bin/Notebooks/helloFeatureClass.ipynb b/bin/Notebooks/helloFeatureClass.ipynb index 5e60aa0a..0316df6a 100644 --- a/bin/Notebooks/helloFeatureClass.ipynb +++ b/bin/Notebooks/helloFeatureClass.ipynb @@ -267,9 +267,9 @@ "output_type": "stream", "text": [ "Will calculate the following shape features: \n", - "Elongation\n", - "\n", + "Maximum2DDiameterSlice\n", "\n", + " Calculate the largest pairwise euclidean distance between tumor surface voxels in the row-column plane.\n", " \n", "Compactness1\n", "\n", @@ -283,6 +283,32 @@ " ratio of volume to the :math:`\\sqrt{\\text{surface area}^3}`. This is a measure of the\n", " compactness of the shape of the image ROI\n", " \n", + "Maximum3DDiameter\n", + "\n", + " Calculate the largest pairwise euclidean distance between tumor surface voxels.\n", + " Also known as Feret Diameter.\n", + " \n", + "Flatness\n", + "\n", + "\n", + " \n", + "Sphericity\n", + "\n", + " Calculate the Sphericity of the tumor region.\n", + "\n", + " :math:`sphericity = \\frac{\\pi^{\\frac{1}{3}}(6V)^{\\frac{2}{3}}}{A}`\n", + "\n", + " Sphericity is a measure of the roundness of the shape of the tumor region\n", + " relative to a sphere. This is another measure of the compactness of a tumor.\n", + " \n", + "Maximum2DDiameterRow\n", + "\n", + " Calculate the largest pairwise euclidean distance between tumor surface voxels in the column-slice plane.\n", + " \n", + "Elongation\n", + "\n", + "\n", + " \n", "SurfaceArea\n", "\n", " Calculate the surface area of the tumor region in square millimeters.\n", @@ -297,9 +323,13 @@ " :math:`b_i` and :math:`c_i`\n", "\n", " \n", - "Maximum2DDiameterSlice\n", + "Volume\n", + "\n", + " Calculate the volume of the tumor region in cubic millimeters.\n", + " \n", + "Roundness\n", + "\n", "\n", - " Calculate the largest pairwise euclidean distance between tumor surface voxels in the row-column plane.\n", " \n", "Compactness2\n", "\n", @@ -312,46 +342,16 @@ " independent of scale and orientation. This is a measure of the compactness\n", " of the shape of the image ROI.\n", " \n", - "Flatness\n", - "\n", - "\n", - " \n", - "Maximum3DDiameter\n", - "\n", - " Calculate the largest pairwise euclidean distance between tumor surface voxels.\n", - " Also known as Feret Diameter.\n", - " \n", - "Roundness\n", - "\n", - "\n", - " \n", "Maximum2DDiameterColumn\n", "\n", " Calculate the largest pairwise euclidean distance between tumor surface voxels in the row-slice plane.\n", " \n", - "Sphericity\n", - "\n", - " Calculate the Sphericity of the tumor region.\n", - "\n", - " :math:`sphericity = \\frac{\\pi^{\\frac{1}{3}}(6V)^{\\frac{2}{3}}}{A}`\n", - "\n", - " Sphericity is a measure of the roundness of the shape of the tumor region\n", - " relative to a sphere. This is another measure of the compactness of a tumor.\n", - " \n", - "Volume\n", - "\n", - " Calculate the volume of the tumor region in cubic millimeters.\n", - " \n", "SurfaceVolumeRatio\n", "\n", " Calculate the surface area to volume ratio of the tumor region\n", "\n", " :math:`surface\\ to\\ volume\\ ratio = \\frac{A}{V}`\n", " \n", - "Maximum2DDiameterRow\n", - "\n", - " Calculate the largest pairwise euclidean distance between tumor surface voxels in the column-slice plane.\n", - " \n", "SphericalDisproportion\n", "\n", " Calculate the Spherical Disproportion of the tumor region.\n", @@ -382,42 +382,6 @@ "collapsed": false }, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "FAILED: Traceback (most recent call last):\n", - " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/base.py\", line 73, in calculateFeatures\n", - " self.featureValues[feature] = eval(call)\n", - " File \"\", line 1, in \n", - " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/shape.py\", line 221, in getMaximum2DDiameterSliceFeatureValue\n", - " return self._getMaximum2Ddiameter(0)\n", - " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/shape.py\", line 126, in _getMaximum2Ddiameter\n", - " for i in numpy.unique(a[:, dim]):\n", - "IndexError: too many indices for array\n", - "\n", - "FAILED: Traceback (most recent call last):\n", - " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/base.py\", line 73, in calculateFeatures\n", - " self.featureValues[feature] = eval(call)\n", - " File \"\", line 1, in \n", - " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/shape.py\", line 228, in getMaximum2DDiameterColumnFeatureValue\n", - " return self._getMaximum2Ddiameter(1)\n", - " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/shape.py\", line 126, in _getMaximum2Ddiameter\n", - " for i in numpy.unique(a[:, dim]):\n", - "IndexError: too many indices for array\n", - "\n", - "FAILED: Traceback (most recent call last):\n", - " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/base.py\", line 73, in calculateFeatures\n", - " self.featureValues[feature] = eval(call)\n", - " File \"\", line 1, in \n", - " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/shape.py\", line 235, in getMaximum2DDiameterRowFeatureValue\n", - " return self._getMaximum2Ddiameter(2)\n", - " File \"/Users/mader/anaconda/lib/python3.5/site-packages/pyradiomics-1.0.1.post5.dev0+g72ac3cb-py3.5.egg/radiomics/shape.py\", line 126, in _getMaximum2Ddiameter\n", - " for i in numpy.unique(a[:, dim]):\n", - "IndexError: too many indices for array\n", - "\n" - ] - }, { "name": "stdout", "output_type": "stream", @@ -425,19 +389,19 @@ "Calculating shape features...\n", "done\n", "Calculated shape features: \n", - " Elongation : 1.7789885567018646\n", + " Maximum2DDiameterSlice : 47.2187913633\n", " Compactness1 : 26.7546787215\n", - " SurfaceArea : 6438.82160378\n", - " Maximum2DDiameterSlice : nan\n", - " Compactness2 : 0.114127701901\n", - " Flatness : 1.2191850589688844\n", " Maximum3DDiameter : 65.53661458728622\n", - " Roundness : 0.6146906661500379\n", - " Maximum2DDiameterColumn : nan\n", + " Flatness : 1.2191850589688844\n", " Sphericity : 0.485061744222\n", + " Maximum2DDiameterRow : 61.5801767135\n", + " Elongation : 1.7789885567018646\n", + " SurfaceArea : 6438.82160378\n", " Volume : 16412.65869140624\n", + " Roundness : 0.6146906661500379\n", + " Compactness2 : 0.114127701901\n", + " Maximum2DDiameterColumn : 44.5487904052\n", " SurfaceVolumeRatio : 0.392308261863\n", - " Maximum2DDiameterRow : nan\n", " SphericalDisproportion : 2.06159321347\n" ] } @@ -471,7 +435,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "calculate GLCM: 100%|██████████| 33/33 [00:00<00:00, 44.78it/s]\n" + "calculate GLCM: 100%|██████████████████████████████████████████████████████████████████| 33/33 [00:00<00:00, 51.40it/s]\n" ] } ], @@ -495,48 +459,28 @@ "output_type": "stream", "text": [ "Will calculate the following GLCM features: \n", - "ClusterTendency\n", - "\n", - " Using coefficients :math:`\\mu_x` and :math:`\\mu_y`, calculate and return the mean Cluster Tendency.\n", - "\n", - " :math:`cluster\\ prominence = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{\\big(i+j-\\mu_x(i)-\\mu_y(j)\\big)^2p(i,j)}`\n", - "\n", - " Cluster Tendency is a measure of groupings of voxels with similar gray-level values.\n", - " \n", - "Autocorrelation\n", - "\n", - " Calculate and return the mean Autocorrelation.\n", - "\n", - " :math:`autocorrelation = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{p(i,j)ij}`\n", - "\n", - " Autocorrelation is a measure of the magnitude of the\n", - " fineness and coarseness of texture.\n", - " \n", - "AverageIntensity\n", - "\n", - " Return the mean gray level intensity of the :math:`i` distribution.\n", - "\n", - " :math:`\\mu_x = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{p(i,j)i}`\n", + "SumSquares\n", "\n", - " N.B. As this formula represents the average of the distribution of :math:`i`, it is independent from the\n", - " distribution of :math:`j`. Therefore, only use this formula if the GLCM is symmetrical, where both distrubutions\n", - " are equal.\n", - " \n", - "SumEntropy\n", + " Using coefficients :math:`i` and math:`\\mu_x`, calculate and return the mean Sum of Squares (also known as\n", + " Variance) of the :math:`i` distribution.\n", "\n", - " Using coefficient :math:`p_{x+y}`, calculate and return the mean Sum Entropy.\n", + " :math:`sum\\ squares = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{(i-\\mu_x)^2p(i,j)}`\n", "\n", - " :math:`sum\\ entropy = \\displaystyle\\sum^{2N_g}_{k=2}{p_{x+y}(k)\\log_2\\big(p_{x+y}(k)+\\epsilon\\big)}`\n", + " Sum of Squares or Variance is a measure in the distribution of neigboring intensity level pairs\n", + " about the mean intensity level in the GLCM.\n", "\n", - " Sum Entropy is a sum of neighborhood intensity value differences.\n", + " N.B. This formula represents the variance of the distribution of :math:`i` and is independent from the distribution\n", + " of :math:`j`. Therefore, only use this formula if the GLCM is symmetrical, where VAR(i) is equal to VAR(j).\n", " \n", - "Entropy\n", + "SumAverage\n", "\n", - " Calculate and return the mean Entropy.\n", + " Coefficient :math:`p_{x+y}`, calculate and return the mean Sum Average.\n", "\n", - " :math:`entropy = -\\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{p(i,j)\\log_2\\big(p(i,j)+\\epsilon\\big)}`\n", + " :math:`sum\\ average = \\displaystyle\\sum^{2N_g}_{k=2}{p_{x+y}(k)k}`\n", "\n", - " Entropy is a measure of the randomness/variability in neighborhood intensity values.\n", + " Sum Average measures the relationship between occurrences of pairs\n", + " with lower intensity values and occurrences of pairs with higher intensity\n", + " values.\n", " \n", "Energy\n", "\n", @@ -549,35 +493,32 @@ " of intensity value pairs in the image that neighbor each other at\n", " higher frequencies.\n", " \n", - "Homogeneity2\n", + "SumEntropy\n", "\n", - " Calculate and return the mean Homogeneity 2.\n", + " Using coefficient :math:`p_{x+y}`, calculate and return the mean Sum Entropy.\n", "\n", - " :math:`homogeneity\\ 2 = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{\\frac{p(i,j)}{1+|i-j|^2}}`\n", + " :math:`sum\\ entropy = \\displaystyle\\sum^{2N_g}_{k=2}{p_{x+y}(k)\\log_2\\big(p_{x+y}(k)+\\epsilon\\big)}`\n", "\n", - " Homogeneity 2 is a measure of the similarity in intensity values\n", - " for neighboring voxels.\n", + " Sum Entropy is a sum of neighborhood intensity value differences.\n", " \n", - "SumVariance2\n", + "AverageIntensity\n", "\n", - " Using coefficients :math:`p_{x+y}` and SumAvarage (SA) calculate and return the mean Sum Variance 2.\n", - " :math:`sum\\ variance\\ 2 = \\displaystyle\\sum^{2N_g}_{k=2}{(k-SA)^2p_{x+y}(k)}`\n", + " Return the mean gray level intensity of the :math:`i` distribution.\n", "\n", - " Sum Variance 2 is a measure of heterogeneity that places higher weights on\n", - " neighboring intensity level pairs that deviate more from the mean.\n", + " :math:`\\mu_x = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{p(i,j)i}`\n", "\n", - " This formula differs from SumVariance in that instead of subtracting the SumEntropy from the intensity,\n", - " it subtracts the SumAvarage, which is the mean of intensities and not its entropy\n", + " N.B. As this formula represents the average of the distribution of :math:`i`, it is independent from the\n", + " distribution of :math:`j`. Therefore, only use this formula if the GLCM is symmetrical, where both distrubutions\n", + " are equal.\n", " \n", - "Homogeneity1\n", + "Id\n", "\n", - " Calculate and return the mean Homogeneity 1.\n", + " Calculate and return the mean Inverse Difference.\n", "\n", - " :math:`homogeneity\\ 1 = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{\\frac{p(i,j)}{1+|i-j|}}`\n", + " :math:`ID = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{ \\frac{\\textbf{P}(i,j)}{1+|i-j|} }`\n", "\n", - " Homogeneity 1 is a measure of the similarity in intensity values for\n", - " neighboring voxels. It is a measure of local homogeneity that increases\n", - " with less contrast in the window.\n", + " ID (inverse difference) is another measure of the local homogeneity of an image.\n", + " With more uniform gray levels, the denominator will remain low, resulting in a higher overall value.\n", " \n", "MaximumProbability\n", "\n", @@ -588,33 +529,26 @@ " Maximum Probability is occurrences of the most predominant pair of\n", " neighboring intensity values.\n", " \n", - "ClusterShade\n", - "\n", - " Using coefficients :math:`\\mu_x` and :math:`\\mu_y`, calculate and return the mean Cluster Shade.\n", - "\n", - " :math:`cluster\\ shade = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{\\big(i+j-\\mu_x(i)-\\mu_y(j)\\big)^3p(i,j)}`\n", - "\n", - " Cluster Shade is a measure of the skewness and uniformity of the GLCM.\n", - " A higher cluster shade implies greater asymmetry about the mean.\n", - " \n", - "SumAverage\n", + "Idmn\n", "\n", - " Coefficient :math:`p_{x+y}`, calculate and return the mean Sum Average.\n", + " Calculate and return the mean Inverse Difference Moment Normalized.\n", "\n", - " :math:`sum\\ average = \\displaystyle\\sum^{2N_g}_{k=2}{p_{x+y}(k)k}`\n", + " :math:`IDMN = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{ \\frac{p(i,j)}{1+\\left(\\frac{|i-j|^2}{N_g^2}\\right)} }`\n", "\n", - " Sum Average measures the relationship between occurrences of pairs\n", - " with lower intensity values and occurrences of pairs with higher intensity\n", - " values.\n", + " IDMN (inverse difference moment normalized) is a measure of the local\n", + " homogeneity of an image. IDMN weights are the inverse of the Contrast\n", + " weights (decreasing exponentially from the diagonal :math:`i=j` in the GLCM).\n", + " Unlike Homogeneity2, IDMN normalizes the square of the difference between\n", + " neighboring intensity values by dividing over the square of the total\n", + " number of discrete intensity values.\n", " \n", - "DifferenceVariance\n", + "Entropy\n", "\n", - " Using coefficients :math:`p_{x-y}` and DifferenceAverage (DA) calculate and return the mean Difference Variance.\n", + " Calculate and return the mean Entropy.\n", "\n", - " :math:`Difference\\ variance = \\displaystyle\\sum^{N_g-1}_{k=0}{(1-DA)^2\\textbf{P}_{x-y}(k)}`\n", + " :math:`entropy = -\\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{p(i,j)\\log_2\\big(p(i,j)+\\epsilon\\big)}`\n", "\n", - " Difference Variance is a measure of heterogeneity that places higher weights on\n", - " differing intensity level pairs that deviate more from the mean.\n", + " Entropy is a measure of the randomness/variability in neighborhood intensity values.\n", " \n", "Idn\n", "\n", @@ -627,63 +561,63 @@ " between the neighboring intensity values by dividing over the total number\n", " of discrete intensity values.\n", " \n", - "ClusterProminence\n", + "ClusterShade\n", "\n", - " Using coefficients :math:`\\mu_x` and :math:`\\mu_y`, calculate and return the mean Cluster Prominence.\n", + " Using coefficients :math:`\\mu_x` and :math:`\\mu_y`, calculate and return the mean Cluster Shade.\n", "\n", - " :math:`cluster\\ prominence = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{\\big( i+j-\\mu_x(i)-\\mu_y(j)\\big)^4p(i,j)}`\n", + " :math:`cluster\\ shade = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{\\big(i+j-\\mu_x(i)-\\mu_y(j)\\big)^3p(i,j)}`\n", "\n", - " Cluster Prominence is a measure of the skewness and asymmetry of the GLCM.\n", - " A higher values implies more asymmetry about the mean while a lower value\n", - " indicates a peak near the mean value and less variation about the mean.\n", + " Cluster Shade is a measure of the skewness and uniformity of the GLCM.\n", + " A higher cluster shade implies greater asymmetry about the mean.\n", " \n", - "SumSquares\n", + "Imc1\n", "\n", - " Using coefficients :math:`i` and math:`\\mu_x`, calculate and return the mean Sum of Squares (also known as\n", - " Variance) of the :math:`i` distribution.\n", + " Using coefficients :math:`HX`, :math:`HY`, :math:`HXY` and :math:`HXY1`, calculate and return the mean Informal\n", + " Measure of Correlation 1.\n", "\n", - " :math:`sum\\ squares = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{(i-\\mu_x)^2p(i,j)}`\n", + " :math:`IMC\\ 1 = \\frac{HXY-HXY1}{\\max\\{HX,HY\\}}`\n", + " \n", + "ClusterTendency\n", "\n", - " Sum of Squares or Variance is a measure in the distribution of neigboring intensity level pairs\n", - " about the mean intensity level in the GLCM.\n", + " Using coefficients :math:`\\mu_x` and :math:`\\mu_y`, calculate and return the mean Cluster Tendency.\n", "\n", - " N.B. This formula represents the variance of the distribution of :math:`i` and is independent from the distribution\n", - " of :math:`j`. Therefore, only use this formula if the GLCM is symmetrical, where VAR(i) is equal to VAR(j).\n", + " :math:`cluster\\ prominence = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{\\big(i+j-\\mu_x(i)-\\mu_y(j)\\big)^2p(i,j)}`\n", + "\n", + " Cluster Tendency is a measure of groupings of voxels with similar gray-level values.\n", " \n", - "Id\n", + "DifferenceVariance\n", "\n", - " Calculate and return the mean Inverse Difference.\n", + " Using coefficients :math:`p_{x-y}` and DifferenceAverage (DA) calculate and return the mean Difference Variance.\n", "\n", - " :math:`ID = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{ \\frac{\\textbf{P}(i,j)}{1+|i-j|} }`\n", + " :math:`Difference\\ variance = \\displaystyle\\sum^{N_g-1}_{k=0}{(1-DA)^2\\textbf{P}_{x-y}(k)}`\n", "\n", - " ID (inverse difference) is another measure of the local homogeneity of an image.\n", - " With more uniform gray levels, the denominator will remain low, resulting in a higher overall value.\n", + " Difference Variance is a measure of heterogeneity that places higher weights on\n", + " differing intensity level pairs that deviate more from the mean.\n", " \n", - "Idm\n", + "Homogeneity1\n", "\n", - " Calculate and return the mean Inverse Difference Moment.\n", + " Calculate and return the mean Homogeneity 1.\n", "\n", - " :math:`IDM = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{ \\frac{\\textbf{P}(i,j)}{1+|i-j|^2} }`\n", + " :math:`homogeneity\\ 1 = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{\\frac{p(i,j)}{1+|i-j|}}`\n", "\n", - " IDM (inverse difference moment) is a measure of the local\n", - " homogeneity of an image. IDM weights are the inverse of the Contrast\n", - " weights (decreasing exponentially from the diagonal i=j in the GLCM).\n", + " Homogeneity 1 is a measure of the similarity in intensity values for\n", + " neighboring voxels. It is a measure of local homogeneity that increases\n", + " with less contrast in the window.\n", " \n", - "InverseVariance\n", + "Imc2\n", "\n", - " Calculate and return the mean Inverse Variance.\n", + " Using coefficients :math:`HXY` and :math:`HXY2`, calculate and return the mean Informal Measure of Correlation 2.\n", "\n", - " :math:`inverse\\ variance = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{\\frac{p(i,j)}{|i-j|^2}}, i \\neq j`\n", + " :math:`IMC\\ 2 = \\sqrt{1-e^{-2(HXY2-HXY)}}`\n", " \n", - "Dissimilarity\n", + "SumVariance\n", "\n", - " Calculate and return the mean Dissimilarity.\n", + " Using coefficients :math:`p_{x+y}` and SumEntropy (SE) calculate and return the mean Sum Variance.\n", "\n", - " :math:`dissimilarity = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{|i-j|p(i,j)}`\n", + " :math:`sum\\ variance = \\displaystyle\\sum^{2N_g}_{k=2}{(k-SE)^2p_{x+y}(k)}`\n", "\n", - " Dissimilarity is a measure of local intensity variation defined as the mean absolute difference between the\n", - " neighbouring pairs. A larger value correlates with a greater disparity in intensity values\n", - " among neighboring voxels.\n", + " Sum Variance is a measure of heterogeneity that places higher weights on\n", + " neighboring intensity level pairs that deviate more from the mean.\n", " \n", "Contrast\n", "\n", @@ -695,36 +629,26 @@ " values away from the diagonal :math:`(i = j)`. A larger value correlates with\n", " a greater disparity in intensity values among neighboring voxels.\n", " \n", - "SumVariance\n", - "\n", - " Using coefficients :math:`p_{x+y}` and SumEntropy (SE) calculate and return the mean Sum Variance.\n", - "\n", - " :math:`sum\\ variance = \\displaystyle\\sum^{2N_g}_{k=2}{(k-SE)^2p_{x+y}(k)}`\n", - "\n", - " Sum Variance is a measure of heterogeneity that places higher weights on\n", - " neighboring intensity level pairs that deviate more from the mean.\n", - " \n", - "DifferenceEntropy\n", + "DifferenceAverage\n", "\n", - " Using coefficient :math:`p_{x-y}`, calculate and return the mean Difference Entropy.\n", + " Using coefficient :math:`p_{x-y}`, calculate and return the mean Difference Average.\n", "\n", - " :math:`difference\\ entropy = \\displaystyle\\sum^{N_g-1}_{k=0}{p_{x-y}(k)\\log_2\\big(p_{x-y}(k)+\\epsilon\\big)}`\n", + " :math:`Difference\\ average = \\displaystyle\\sum^{N_g-1}_{k=0}{k\\textbf{P}_{x-y}(k)}`\n", "\n", - " Difference Entropy is a measure of the randomness/variability\n", - " in neighborhood intensity value differences.\n", + " Difference Average measures the relationship between occurrences of pairs\n", + " with similar intensity values and occurrences of pairs with differing intensity\n", + " values.\n", " \n", - "Idmn\n", + "SumVariance2\n", "\n", - " Calculate and return the mean Inverse Difference Moment Normalized.\n", + " Using coefficients :math:`p_{x+y}` and SumAvarage (SA) calculate and return the mean Sum Variance 2.\n", + " :math:`sum\\ variance\\ 2 = \\displaystyle\\sum^{2N_g}_{k=2}{(k-SA)^2p_{x+y}(k)}`\n", "\n", - " :math:`IDMN = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{ \\frac{p(i,j)}{1+\\left(\\frac{|i-j|^2}{N_g^2}\\right)} }`\n", + " Sum Variance 2 is a measure of heterogeneity that places higher weights on\n", + " neighboring intensity level pairs that deviate more from the mean.\n", "\n", - " IDMN (inverse difference moment normalized) is a measure of the local\n", - " homogeneity of an image. IDMN weights are the inverse of the Contrast\n", - " weights (decreasing exponentially from the diagonal :math:`i=j` in the GLCM).\n", - " Unlike Homogeneity2, IDMN normalizes the square of the difference between\n", - " neighboring intensity values by dividing over the square of the total\n", - " number of discrete intensity values.\n", + " This formula differs from SumVariance in that instead of subtracting the SumEntropy from the intensity,\n", + " it subtracts the SumAvarage, which is the mean of intensities and not its entropy\n", " \n", "Correlation\n", "\n", @@ -736,28 +660,68 @@ " Correlation is a value between 0 (uncorrelated) and 1 (perfectly correlated) showing the\n", " linear dependency of gray level values to their respective voxels in the GLCM.\n", " \n", - "Imc1\n", + "ClusterProminence\n", "\n", - " Using coefficients :math:`HX`, :math:`HY`, :math:`HXY` and :math:`HXY1`, calculate and return the mean Informal\n", - " Measure of Correlation 1.\n", + " Using coefficients :math:`\\mu_x` and :math:`\\mu_y`, calculate and return the mean Cluster Prominence.\n", "\n", - " :math:`IMC\\ 1 = \\frac{HXY-HXY1}{\\max\\{HX,HY\\}}`\n", + " :math:`cluster\\ prominence = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{\\big( i+j-\\mu_x(i)-\\mu_y(j)\\big)^4p(i,j)}`\n", + "\n", + " Cluster Prominence is a measure of the skewness and asymmetry of the GLCM.\n", + " A higher values implies more asymmetry about the mean while a lower value\n", + " indicates a peak near the mean value and less variation about the mean.\n", " \n", - "Imc2\n", + "InverseVariance\n", "\n", - " Using coefficients :math:`HXY` and :math:`HXY2`, calculate and return the mean Informal Measure of Correlation 2.\n", + " Calculate and return the mean Inverse Variance.\n", "\n", - " :math:`IMC\\ 2 = \\sqrt{1-e^{-2(HXY2-HXY)}}`\n", + " :math:`inverse\\ variance = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{\\frac{p(i,j)}{|i-j|^2}}, i \\neq j`\n", " \n", - "DifferenceAverage\n", + "Homogeneity2\n", "\n", - " Using coefficient :math:`p_{x-y}`, calculate and return the mean Difference Average.\n", + " Calculate and return the mean Homogeneity 2.\n", "\n", - " :math:`Difference\\ average = \\displaystyle\\sum^{N_g-1}_{k=0}{k\\textbf{P}_{x-y}(k)}`\n", + " :math:`homogeneity\\ 2 = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{\\frac{p(i,j)}{1+|i-j|^2}}`\n", "\n", - " Difference Average measures the relationship between occurrences of pairs\n", - " with similar intensity values and occurrences of pairs with differing intensity\n", - " values.\n", + " Homogeneity 2 is a measure of the similarity in intensity values\n", + " for neighboring voxels.\n", + " \n", + "DifferenceEntropy\n", + "\n", + " Using coefficient :math:`p_{x-y}`, calculate and return the mean Difference Entropy.\n", + "\n", + " :math:`difference\\ entropy = \\displaystyle\\sum^{N_g-1}_{k=0}{p_{x-y}(k)\\log_2\\big(p_{x-y}(k)+\\epsilon\\big)}`\n", + "\n", + " Difference Entropy is a measure of the randomness/variability\n", + " in neighborhood intensity value differences.\n", + " \n", + "Dissimilarity\n", + "\n", + " Calculate and return the mean Dissimilarity.\n", + "\n", + " :math:`dissimilarity = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{|i-j|p(i,j)}`\n", + "\n", + " Dissimilarity is a measure of local intensity variation defined as the mean absolute difference between the\n", + " neighbouring pairs. A larger value correlates with a greater disparity in intensity values\n", + " among neighboring voxels.\n", + " \n", + "Idm\n", + "\n", + " Calculate and return the mean Inverse Difference Moment.\n", + "\n", + " :math:`IDM = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{ \\frac{\\textbf{P}(i,j)}{1+|i-j|^2} }`\n", + "\n", + " IDM (inverse difference moment) is a measure of the local\n", + " homogeneity of an image. IDM weights are the inverse of the Contrast\n", + " weights (decreasing exponentially from the diagonal i=j in the GLCM).\n", + " \n", + "Autocorrelation\n", + "\n", + " Calculate and return the mean Autocorrelation.\n", + "\n", + " :math:`autocorrelation = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_g}_{j=1}{p(i,j)ij}`\n", + "\n", + " Autocorrelation is a measure of the magnitude of the\n", + " fineness and coarseness of texture.\n", " \n" ] } @@ -784,34 +748,34 @@ "Calculating GLCM features...\n", "done\n", "Calculated GLCM features: \n", - " ClusterTendency : 103.142793792\n", - " Autocorrelation : 292.684050471\n", - " AverageIntensity : 17.1242601309\n", - " SumEntropy : 5.31547876648\n", - " DifferenceAverage : 5.58932678922\n", - " Entropy : 8.79428086119\n", - " Energy : 0.00290880217681\n", - " Homogeneity2 : 0.189156155892\n", - " SumVariance2 : 103.142793792\n", - " Homogeneity1 : 0.276140402104\n", - " MaximumProbability : 0.00792784235012\n", - " ClusterShade : -52.9707943386\n", + " SumSquares : 39.9781084143\n", " SumAverage : 33.4497492152\n", - " DifferenceVariance : 17.6107741076\n", + " Energy : 0.00290880217681\n", " Idn : 0.866370546902\n", - " ClusterProminence : 26251.1709801\n", - " SumSquares : 39.9781084143\n", + " AverageIntensity : 17.1242601309\n", " Id : 0.276140402104\n", - " Idm : 0.189156155892\n", - " InverseVariance : 0.188666637795\n", + " SumVariance : 895.891808819\n", " Dissimilarity : 5.58932678922\n", + " Entropy : 8.79428086119\n", + " SumEntropy : 5.31547876648\n", + " ClusterShade : -52.9707943386\n", + " Imc2 : 0.692033706271\n", + " ClusterTendency : 103.142793792\n", + " DifferenceVariance : 17.6107741076\n", + " Homogeneity1 : 0.276140402104\n", + " Imc1 : -0.091940840043\n", " Contrast : 52.2310659277\n", - " SumVariance : 895.891808819\n", " DifferenceEntropy : 3.79686113536\n", - " Imc2 : 0.692033706271\n", + " DifferenceAverage : 5.58932678922\n", + " SumVariance2 : 103.142793792\n", " Correlation : 0.335214788202\n", + " ClusterProminence : 26251.1709801\n", + " InverseVariance : 0.188666637795\n", + " Homogeneity2 : 0.189156155892\n", + " MaximumProbability : 0.00792784235012\n", " Idmn : 0.957796447609\n", - " Imc1 : -0.091940840043\n" + " Idm : 0.189156155892\n", + " Autocorrelation : 292.684050471\n" ] } ], @@ -860,42 +824,73 @@ "output_type": "stream", "text": [ "Will calculate the following GLRLM features: \n", - "RunLengthNonUniformity\n", + "GrayLevelNonUniformityNormalized\n", "\n", - " Calculate and return the mean Run Length Non-Uniformity (RLN) value for all GLRLMs.\n", + " Calculate and return the Gray Level Non-Uniformity Normalized (GLNN) value.\n", "\n", - " :math:`RLN = \\frac{\\sum^{N_r}_{j=1}\\left(\\sum^{N_g}_{i=1}{\\textbf{P}(i,j|\\theta)}\\right)^2}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}}`\n", + " :math:`GLNN = \\frac{\\sum^{N_g}_{i=1}\\left(\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}\\right)^2}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}^2}`\n", + "\n", + " Measures the similarity of gray-level intensity values in the image, where a lower GLNN value\n", + " correlates with a greater similarity in intensity values. This is the normalized version of the GLN formula.\n", + " \n", + "ShortRunHighGrayLevelEmphasis\n", + "\n", + " Calculate and return the mean Short Run High Gray Level Emphasis (SRHGLE) value for all GLRLMs.\n", + "\n", + " :math:`SRHGLE = \\frac{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\frac{\\textbf{P}(i,j|\\theta)i^2}{j^2}}}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}}`\n", + "\n", + " Measures the joint distribution of shorter run lengths with higher gray-level values.\n", + " \n", + "RunLengthNonUniformityNormalized\n", + "\n", + " Calculate and return the mean Run Length Non-Uniformity Normalized (RLNN) value for all GLRLMs.\n", + "\n", + " :math:`RLNN = \\frac{\\sum^{N_r}_{j=1}\\left(\\sum^{N_g}_{i=1}{\\textbf{P}(i,j|\\theta)}\\right)^2}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}}`\n", "\n", " Measures the similarity of run lengths throughout the image, with a lower value indicating\n", - " more homogeneity among run lengths in the image.\n", + " more homogeneity among run lengths in the image. This is the normalized version of the RLN formula.\n", " \n", - "LongRunEmphasis\n", + "RunEntropy\n", "\n", - " Calculate and return the mean Long Run Emphasis (LRE) value for all GLRLMs.\n", + " Calculate and return the Run Entropy (RE) value.\n", "\n", - " :math:`LRE = \\frac{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)j^2}}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}}`\n", + " :math:`RE = -\\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_r}_{j=1}{p(i,j|\\theta)\\log_{2}(p(i,j|\\theta)+\\epsilon)}`\n", "\n", - " A measure of the distribution of long run lengths, with a greater value indicative\n", - " of longer run lengths and more coarse structural textures.\n", + " Here, :math:`\\epsilon` is an arbitrarily small positive number (:math:`\\approx 2.2\\times10^{-16}`).\n", " \n", - "LowGrayLevelRunEmphasis\n", + "HighGrayLevelRunEmphasis\n", "\n", - " Calculate and return the mean Low Gray Level Run Emphasis (LGLRE) value for all GLRLMs.\n", + " Calculate and return the mean High Gray Level Run Emphasis (HGLRE) value for all GLRLMs.\n", "\n", - " :math:`LGLRE = \\frac{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\frac{\\textbf{P}(i,j|\\theta)}{i^2}}}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}}`\n", + " :math:`HGLRE = \\frac{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)i^2}}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}}`\n", "\n", - " Measures the distribution of low gray-level values, with a higher value indicating a greater\n", - " concentration of low gray-level values in the image.\n", + " Measures the distribution of the higher gray-level values, with a higher value indicating\n", + " a greater concentration of high gray-level values in the image.\n", " \n", - "RunVariance\n", + "LongRunHighGrayLevelEmphasis\n", "\n", - " Calculate and return the Run Variance (RV) value.\n", + " Calculate and return the mean Long Run High Gray Level Emphasis (LRHGLE) value for all GLRLMs.\n", "\n", - " :math:`RV = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_r}_{j=1}{p(i,j|\\theta)(j - \\mu)^2}`, where\n", + " :math:`LRHGLRE = \\frac{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)i^2j^2}}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}}`\n", "\n", - " :math:`\\mu = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_r}_{j=1}{p(i,j|\\theta)j}`\n", + " Measures the joint distribution of long run lengths with higher gray-level values.\n", + " \n", + "ShortRunLowGrayLevelEmphasis\n", "\n", - " Measures the variance in runs for the run lengths.\n", + " Calculate and return the mean Short Run Low Gray Level Emphasis (SRLGLE) value for all GLRLMs.\n", + "\n", + " :math:`SRLGLE = \\frac{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\frac{\\textbf{P}(i,j|\\theta)}{i^2j^2}}}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}}`\n", + "\n", + " Measures the joint distribution of shorter run lengths with lower gray-level values.\n", + " \n", + "RunLengthNonUniformity\n", + "\n", + " Calculate and return the mean Run Length Non-Uniformity (RLN) value for all GLRLMs.\n", + "\n", + " :math:`RLN = \\frac{\\sum^{N_r}_{j=1}\\left(\\sum^{N_g}_{i=1}{\\textbf{P}(i,j|\\theta)}\\right)^2}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}}`\n", + "\n", + " Measures the similarity of run lengths throughout the image, with a lower value indicating\n", + " more homogeneity among run lengths in the image.\n", " \n", "GrayLevelVariance\n", "\n", @@ -915,14 +910,6 @@ "\n", " Measures the homogeneity and distribution of runs of an image.\n", " \n", - "LongRunLowGrayLevelEmphasis\n", - "\n", - " Calculate and return the mean Long Run Low Gray Level Emphasis (LRLGLE) value for all GLRLMs.\n", - "\n", - " :math:`LRLGLRE = \\frac{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\frac{\\textbf{P}(i,j|\\theta)j^2}{i^2}}}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}}`\n", - "\n", - " Measures the joint distribution of long run lengths with lower gray-level values.\n", - " \n", "GrayLevelNonUniformity\n", "\n", " Calculate and return the mean Gray Level Non-Uniformity (GLN) value for all GLRLMs.\n", @@ -932,73 +919,50 @@ " Measures the similarity of gray-level intensity values in the image, where a lower GLN value\n", " correlates with a greater similarity in intensity values.\n", " \n", - "RunLengthNonUniformityNormalized\n", + "LongRunEmphasis\n", "\n", - " Calculate and return the mean Run Length Non-Uniformity Normalized (RLNN) value for all GLRLMs.\n", + " Calculate and return the mean Long Run Emphasis (LRE) value for all GLRLMs.\n", "\n", - " :math:`RLNN = \\frac{\\sum^{N_r}_{j=1}\\left(\\sum^{N_g}_{i=1}{\\textbf{P}(i,j|\\theta)}\\right)^2}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}}`\n", + " :math:`LRE = \\frac{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)j^2}}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}}`\n", "\n", - " Measures the similarity of run lengths throughout the image, with a lower value indicating\n", - " more homogeneity among run lengths in the image. This is the normalized version of the RLN formula.\n", + " A measure of the distribution of long run lengths, with a greater value indicative\n", + " of longer run lengths and more coarse structural textures.\n", " \n", - "HighGrayLevelRunEmphasis\n", + "LowGrayLevelRunEmphasis\n", "\n", - " Calculate and return the mean High Gray Level Run Emphasis (HGLRE) value for all GLRLMs.\n", + " Calculate and return the mean Low Gray Level Run Emphasis (LGLRE) value for all GLRLMs.\n", "\n", - " :math:`HGLRE = \\frac{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)i^2}}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}}`\n", + " :math:`LGLRE = \\frac{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\frac{\\textbf{P}(i,j|\\theta)}{i^2}}}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}}`\n", "\n", - " Measures the distribution of the higher gray-level values, with a higher value indicating\n", - " a greater concentration of high gray-level values in the image.\n", + " Measures the distribution of low gray-level values, with a higher value indicating a greater\n", + " concentration of low gray-level values in the image.\n", " \n", - "LongRunHighGrayLevelEmphasis\n", + "LongRunLowGrayLevelEmphasis\n", "\n", - " Calculate and return the mean Long Run High Gray Level Emphasis (LRHGLE) value for all GLRLMs.\n", + " Calculate and return the mean Long Run Low Gray Level Emphasis (LRLGLE) value for all GLRLMs.\n", "\n", - " :math:`LRHGLRE = \\frac{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)i^2j^2}}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}}`\n", + " :math:`LRLGLRE = \\frac{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\frac{\\textbf{P}(i,j|\\theta)j^2}{i^2}}}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}}`\n", "\n", - " Measures the joint distribution of long run lengths with higher gray-level values.\n", + " Measures the joint distribution of long run lengths with lower gray-level values.\n", " \n", - "ShortRunEmphasis\n", + "RunVariance\n", "\n", - " Calculate and return the mean Short Run Emphasis (SRE) value for all GLRLMs.\n", + " Calculate and return the Run Variance (RV) value.\n", "\n", - " :math:`SRE = \\frac{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\frac{\\textbf{P}(i,j|\\theta)}{i^2}}}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}}`\n", - "\n", - " A measure of the distribution of short run lengths, with a greater value indicative\n", - " of shorter run lengths and more fine textural textures.\n", - " \n", - "GrayLevelNonUniformityNormalized\n", - "\n", - " Calculate and return the Gray Level Non-Uniformity Normalized (GLNN) value.\n", - "\n", - " :math:`GLNN = \\frac{\\sum^{N_g}_{i=1}\\left(\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}\\right)^2}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}^2}`\n", - "\n", - " Measures the similarity of gray-level intensity values in the image, where a lower GLNN value\n", - " correlates with a greater similarity in intensity values. This is the normalized version of the GLN formula.\n", - " \n", - "ShortRunHighGrayLevelEmphasis\n", - "\n", - " Calculate and return the mean Short Run High Gray Level Emphasis (SRHGLE) value for all GLRLMs.\n", - "\n", - " :math:`SRHGLE = \\frac{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\frac{\\textbf{P}(i,j|\\theta)i^2}{j^2}}}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}}`\n", - "\n", - " Measures the joint distribution of shorter run lengths with higher gray-level values.\n", - " \n", - "ShortRunLowGrayLevelEmphasis\n", - "\n", - " Calculate and return the mean Short Run Low Gray Level Emphasis (SRLGLE) value for all GLRLMs.\n", + " :math:`RV = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_r}_{j=1}{p(i,j|\\theta)(j - \\mu)^2}`, where\n", "\n", - " :math:`SRLGLE = \\frac{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\frac{\\textbf{P}(i,j|\\theta)}{i^2j^2}}}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}}`\n", + " :math:`\\mu = \\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_r}_{j=1}{p(i,j|\\theta)j}`\n", "\n", - " Measures the joint distribution of shorter run lengths with lower gray-level values.\n", + " Measures the variance in runs for the run lengths.\n", " \n", - "RunEntropy\n", + "ShortRunEmphasis\n", "\n", - " Calculate and return the Run Entropy (RE) value.\n", + " Calculate and return the mean Short Run Emphasis (SRE) value for all GLRLMs.\n", "\n", - " :math:`RE = -\\displaystyle\\sum^{N_g}_{i=1}\\displaystyle\\sum^{N_r}_{j=1}{p(i,j|\\theta)\\log_{2}(p(i,j|\\theta)+\\epsilon)}`\n", + " :math:`SRE = \\frac{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\frac{\\textbf{P}(i,j|\\theta)}{i^2}}}{\\sum^{N_g}_{i=1}\\sum^{N_r}_{j=1}{\\textbf{P}(i,j|\\theta)}}`\n", "\n", - " Here, :math:`\\epsilon` is an arbitrarily small positive number (:math:`\\approx 2.2\\times10^{-16}`).\n", + " A measure of the distribution of short run lengths, with a greater value indicative\n", + " of shorter run lengths and more fine textural textures.\n", " \n" ] } @@ -1025,22 +989,22 @@ "Calculating GLRLM features...\n", "done\n", "Calculated GLRLM features: \n", - " RunLengthNonUniformity : 3473.88954354\n", - " LongRunEmphasis : 1.22741432468\n", - " LowGrayLevelRunEmphasis : 0.00846567390082\n", - " RunVariance : 0.0849939088453\n", - " GrayLevelVariance : 39.074009627\n", - " RunPercentage : 0.934010152284\n", - " LongRunLowGrayLevelEmphasis : 0.0104694333711\n", - " GrayLevelNonUniformity : 174.640108304\n", + " GrayLevelNonUniformityNormalized : 0.0451916226163\n", + " ShortRunHighGrayLevelEmphasis : 269.366654415\n", " RunLengthNonUniformityNormalized : 0.894736783551\n", + " RunEntropy : 4.91343459806\n", " HighGrayLevelRunEmphasis : 281.50156957\n", " LongRunHighGrayLevelEmphasis : 341.908225705\n", - " ShortRunEmphasis : 0.955813827306\n", - " GrayLevelNonUniformityNormalized : 0.0451916226163\n", - " ShortRunHighGrayLevelEmphasis : 269.366654415\n", " ShortRunLowGrayLevelEmphasis : 0.0080944625119\n", - " RunEntropy : 4.91343459806\n" + " RunLengthNonUniformity : 3473.88954354\n", + " GrayLevelVariance : 39.074009627\n", + " RunPercentage : 0.934010152284\n", + " GrayLevelNonUniformity : 174.640108304\n", + " LongRunEmphasis : 1.22741432468\n", + " LowGrayLevelRunEmphasis : 0.00846567390082\n", + " LongRunLowGrayLevelEmphasis : 0.0104694333711\n", + " RunVariance : 0.0849939088453\n", + " ShortRunEmphasis : 0.955813827306\n" ] } ], @@ -1078,7 +1042,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 19, "metadata": { "collapsed": false }, @@ -1106,7 +1070,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 20, "metadata": { "collapsed": false }, @@ -1115,63 +1079,63 @@ "name": "stdout", "output_type": "stream", "text": [ - " log-sigma-5-0-mm-3D_RootMeanSquared : 1896.44460614\n", - " log-sigma-5-0-mm-3D_Energy : 14878729370.4\n", - " log-sigma-5-0-mm-3D_Uniformity : 0.0902675928609\n", - " log-sigma-5-0-mm-3D_Maximum : 117.414512634\n", - " log-sigma-5-0-mm-3D_Range : 464.759513855\n", - " log-sigma-5-0-mm-3D_Skewness : -0.30549686903\n", - " log-sigma-5-0-mm-3D_Kurtosis : 3.11489160873\n", - " log-sigma-5-0-mm-3D_Median : -99.1174468994\n", - " log-sigma-5-0-mm-3D_Variance : 6483.79391901\n", - " log-sigma-5-0-mm-3D_10Percentile : -211.974316406\n", - " log-sigma-5-0-mm-3D_Entropy : 3.71336391413\n", - " log-sigma-5-0-mm-3D_TotalEnergy : 59028162175.1\n", - " log-sigma-5-0-mm-3D_InterquartileRange : 106.342716217\n", - " log-sigma-5-0-mm-3D_MeanAbsoluteDeviation : 63.4364264458\n", - " log-sigma-5-0-mm-3D_StandardDeviation : 80.5220089107\n", - " log-sigma-5-0-mm-3D_90Percentile : -10.6977561951\n", - " log-sigma-5-0-mm-3D_Minimum : -347.345001221\n", - " log-sigma-5-0-mm-3D_RobustMeanAbsoluteDeviation : 43.2562957783\n", - " log-sigma-5-0-mm-3D_Mean : -105.265625411\n", - " log-sigma-1-0-mm-3D_RootMeanSquared : 1978.94740333\n", - " log-sigma-1-0-mm-3D_Energy : 16201455197.6\n", - " log-sigma-1-0-mm-3D_Uniformity : 0.114235313372\n", - " log-sigma-1-0-mm-3D_Maximum : 164.726760864\n", " log-sigma-1-0-mm-3D_Range : 419.98638916\n", - " log-sigma-1-0-mm-3D_Skewness : -0.220905251704\n", - " log-sigma-1-0-mm-3D_Kurtosis : 3.07182438072\n", - " log-sigma-1-0-mm-3D_Median : -18.9197921753\n", - " log-sigma-1-0-mm-3D_Variance : 3930.90758913\n", + " log-sigma-1-0-mm-3D_MeanAbsoluteDeviation : 49.6646616511\n", " log-sigma-1-0-mm-3D_10Percentile : -104.93405304\n", - " log-sigma-1-0-mm-3D_Entropy : 3.37004955078\n", - " log-sigma-1-0-mm-3D_TotalEnergy : 64275792715.1\n", + " log-sigma-1-0-mm-3D_Skewness : -0.220905251704\n", " log-sigma-1-0-mm-3D_InterquartileRange : 81.8767185211\n", - " log-sigma-1-0-mm-3D_MeanAbsoluteDeviation : 49.6646616511\n", - " log-sigma-1-0-mm-3D_StandardDeviation : 62.6969503974\n", " log-sigma-1-0-mm-3D_90Percentile : 54.7903442383\n", + " log-sigma-1-0-mm-3D_Maximum : 164.726760864\n", + " log-sigma-1-0-mm-3D_RootMeanSquared : 1978.94740333\n", + " log-sigma-1-0-mm-3D_Median : -18.9197921753\n", + " log-sigma-1-0-mm-3D_StandardDeviation : 62.6969503974\n", + " log-sigma-1-0-mm-3D_Entropy : 3.37004955078\n", " log-sigma-1-0-mm-3D_Minimum : -255.259628296\n", + " log-sigma-1-0-mm-3D_TotalEnergy : 64275792715.1\n", + " log-sigma-1-0-mm-3D_Kurtosis : 3.07182438072\n", " log-sigma-1-0-mm-3D_RobustMeanAbsoluteDeviation : 34.3094515237\n", " log-sigma-1-0-mm-3D_Mean : -22.0460274432\n", - " log-sigma-3-0-mm-3D_RootMeanSquared : 1919.01616706\n", - " log-sigma-3-0-mm-3D_Energy : 15235011555.6\n", - " log-sigma-3-0-mm-3D_Uniformity : 0.0906478492348\n", - " log-sigma-3-0-mm-3D_Maximum : 114.296691895\n", + " log-sigma-1-0-mm-3D_Variance : 3930.90758913\n", + " log-sigma-1-0-mm-3D_Uniformity : 0.114235313372\n", + " log-sigma-1-0-mm-3D_Energy : 16201455197.6\n", " log-sigma-3-0-mm-3D_Range : 468.63192749\n", - " log-sigma-3-0-mm-3D_Skewness : -0.498386343995\n", - " log-sigma-3-0-mm-3D_Kurtosis : 3.18336583197\n", - " log-sigma-3-0-mm-3D_Median : -73.3129653931\n", - " log-sigma-3-0-mm-3D_Variance : 6720.06651871\n", + " log-sigma-3-0-mm-3D_MeanAbsoluteDeviation : 64.3312024633\n", " log-sigma-3-0-mm-3D_10Percentile : -197.017340088\n", - " log-sigma-3-0-mm-3D_Entropy : 3.72121444058\n", - " log-sigma-3-0-mm-3D_TotalEnergy : 60441635199.8\n", + " log-sigma-3-0-mm-3D_Skewness : -0.498386343995\n", " log-sigma-3-0-mm-3D_InterquartileRange : 103.158138275\n", - " log-sigma-3-0-mm-3D_MeanAbsoluteDeviation : 64.3312024633\n", - " log-sigma-3-0-mm-3D_StandardDeviation : 81.9760118492\n", " log-sigma-3-0-mm-3D_90Percentile : 13.9173410416\n", + " log-sigma-3-0-mm-3D_Maximum : 114.296691895\n", + " log-sigma-3-0-mm-3D_RootMeanSquared : 1919.01616706\n", + " log-sigma-3-0-mm-3D_Median : -73.3129653931\n", + " log-sigma-3-0-mm-3D_StandardDeviation : 81.9760118492\n", + " log-sigma-3-0-mm-3D_Entropy : 3.72121444058\n", " log-sigma-3-0-mm-3D_Minimum : -354.335235596\n", + " log-sigma-3-0-mm-3D_TotalEnergy : 60441635199.8\n", + " log-sigma-3-0-mm-3D_Kurtosis : 3.18336583197\n", " log-sigma-3-0-mm-3D_RobustMeanAbsoluteDeviation : 43.3779243984\n", - " log-sigma-3-0-mm-3D_Mean : -82.7355469484\n" + " log-sigma-3-0-mm-3D_Mean : -82.7355469484\n", + " log-sigma-3-0-mm-3D_Variance : 6720.06651871\n", + " log-sigma-3-0-mm-3D_Uniformity : 0.0906478492348\n", + " log-sigma-3-0-mm-3D_Energy : 15235011555.6\n", + " log-sigma-5-0-mm-3D_Range : 464.759513855\n", + " log-sigma-5-0-mm-3D_MeanAbsoluteDeviation : 63.4364264458\n", + " log-sigma-5-0-mm-3D_10Percentile : -211.974316406\n", + " log-sigma-5-0-mm-3D_Skewness : -0.30549686903\n", + " log-sigma-5-0-mm-3D_InterquartileRange : 106.342716217\n", + " log-sigma-5-0-mm-3D_90Percentile : -10.6977561951\n", + " log-sigma-5-0-mm-3D_Maximum : 117.414512634\n", + " log-sigma-5-0-mm-3D_RootMeanSquared : 1896.44460614\n", + " log-sigma-5-0-mm-3D_Median : -99.1174468994\n", + " log-sigma-5-0-mm-3D_StandardDeviation : 80.5220089107\n", + " log-sigma-5-0-mm-3D_Entropy : 3.71336391413\n", + " log-sigma-5-0-mm-3D_Minimum : -347.345001221\n", + " log-sigma-5-0-mm-3D_TotalEnergy : 59028162175.1\n", + " log-sigma-5-0-mm-3D_Kurtosis : 3.11489160873\n", + " log-sigma-5-0-mm-3D_RobustMeanAbsoluteDeviation : 43.2562957783\n", + " log-sigma-5-0-mm-3D_Mean : -105.265625411\n", + " log-sigma-5-0-mm-3D_Variance : 6483.79391901\n", + " log-sigma-5-0-mm-3D_Uniformity : 0.0902675928609\n", + " log-sigma-5-0-mm-3D_Energy : 14878729370.4\n" ] } ], @@ -1199,7 +1163,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 21, "metadata": { "collapsed": false }, @@ -1208,13 +1172,13 @@ "name": "stdout", "output_type": "stream", "text": [ - "Calculated firstorder features with wavelet-HLL\n", "Calculated firstorder features with wavelet-LHH\n", - "Calculated firstorder features with wavelet-HHH\n", + "Calculated firstorder features with wavelet-HLL\n", "Calculated firstorder features with wavelet-LHL\n", "Calculated firstorder features with wavelet-LLH\n", "Calculated firstorder features with wavelet-HLH\n", "Calculated firstorder features with wavelet-HHL\n", + "Calculated firstorder features with wavelet-HHH\n", "Calculated firstorder features with wavelet-LLL\n" ] } @@ -1233,7 +1197,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 22, "metadata": { "collapsed": false }, @@ -1242,158 +1206,158 @@ "name": "stdout", "output_type": "stream", "text": [ - " wavelet-HLH_RootMeanSquared : 2000.3397095\n", - " wavelet-HLH_Energy : 16553621990.3\n", - " wavelet-HLH_Uniformity : 0.192969183516\n", - " wavelet-HLH_Maximum : 195.252851267\n", " wavelet-HLH_Range : 449.325547601\n", - " wavelet-HLH_Skewness : -0.109634215846\n", - " wavelet-HLH_Kurtosis : 5.96264006105\n", - " wavelet-HLH_Median : -0.788893809524\n", - " wavelet-HLH_Variance : 1812.89759077\n", + " wavelet-HLH_MeanAbsoluteDeviation : 30.6419982661\n", " wavelet-HLH_10Percentile : -48.7973652241\n", - " wavelet-HLH_Entropy : 2.75501833527\n", - " wavelet-HLH_TotalEnergy : 65672938804.3\n", + " wavelet-HLH_Skewness : -0.109634215846\n", " wavelet-HLH_InterquartileRange : 44.1166822627\n", - " wavelet-HLH_MeanAbsoluteDeviation : 30.6419982661\n", - " wavelet-HLH_StandardDeviation : 42.5781351255\n", " wavelet-HLH_90Percentile : 48.8399961041\n", + " wavelet-HLH_Maximum : 195.252851267\n", + " wavelet-HLH_RootMeanSquared : 2000.3397095\n", + " wavelet-HLH_Median : -0.788893809524\n", + " wavelet-HLH_StandardDeviation : 42.5781351255\n", + " wavelet-HLH_Entropy : 2.75501833527\n", " wavelet-HLH_Minimum : -254.072696334\n", + " wavelet-HLH_TotalEnergy : 65672938804.3\n", + " wavelet-HLH_Kurtosis : 5.96264006105\n", " wavelet-HLH_RobustMeanAbsoluteDeviation : 18.8328798407\n", " wavelet-HLH_Mean : -0.113489262994\n", - " wavelet-HLL_RootMeanSquared : 1995.50607096\n", - " wavelet-HLL_Energy : 16473718010.5\n", - " wavelet-HLL_Uniformity : 0.163587425574\n", - " wavelet-HLL_Maximum : 186.246123128\n", + " wavelet-HLH_Variance : 1812.89759077\n", + " wavelet-HLH_Uniformity : 0.192969183516\n", + " wavelet-HLH_Energy : 16553621990.3\n", + " wavelet-LLH_Range : 1516.85940092\n", + " wavelet-LLH_MeanAbsoluteDeviation : 205.422769392\n", + " wavelet-LLH_10Percentile : -370.145218742\n", + " wavelet-LLH_Skewness : -0.525773815287\n", + " wavelet-LLH_InterquartileRange : 352.67245821\n", + " wavelet-LLH_90Percentile : 297.911610403\n", + " wavelet-LLH_Maximum : 733.850508276\n", + " wavelet-LLH_RootMeanSquared : 2025.7276121\n", + " wavelet-LLH_Median : 62.7368130339\n", + " wavelet-LLH_StandardDeviation : 252.406755064\n", + " wavelet-LLH_Entropy : 5.27888924024\n", + " wavelet-LLH_Minimum : -783.008892644\n", + " wavelet-LLH_TotalEnergy : 67350532534.4\n", + " wavelet-LLH_Kurtosis : 2.69674899921\n", + " wavelet-LLH_RobustMeanAbsoluteDeviation : 146.79059076\n", + " wavelet-LLH_Mean : 9.94109078503\n", + " wavelet-LLH_Variance : 63709.1700017\n", + " wavelet-LLH_Uniformity : 0.0304399667913\n", + " wavelet-LLH_Energy : 16976478846.8\n", " wavelet-HLL_Range : 477.790085389\n", - " wavelet-HLL_Skewness : -0.514166044802\n", - " wavelet-HLL_Kurtosis : 5.09932613055\n", - " wavelet-HLL_Median : -2.81720035764\n", - " wavelet-HLL_Variance : 2328.11665966\n", + " wavelet-HLL_MeanAbsoluteDeviation : 35.7539421526\n", " wavelet-HLL_10Percentile : -62.825323625\n", - " wavelet-HLL_Entropy : 2.95573220857\n", - " wavelet-HLL_TotalEnergy : 65355936931.4\n", + " wavelet-HLL_Skewness : -0.514166044802\n", " wavelet-HLL_InterquartileRange : 53.6721220044\n", - " wavelet-HLL_MeanAbsoluteDeviation : 35.7539421526\n", - " wavelet-HLL_StandardDeviation : 48.2505612367\n", " wavelet-HLL_90Percentile : 50.858801791\n", + " wavelet-HLL_Maximum : 186.246123128\n", + " wavelet-HLL_RootMeanSquared : 1995.50607096\n", + " wavelet-HLL_Median : -2.81720035764\n", + " wavelet-HLL_StandardDeviation : 48.2505612367\n", + " wavelet-HLL_Entropy : 2.95573220857\n", " wavelet-HLL_Minimum : -291.543962261\n", + " wavelet-HLL_TotalEnergy : 65355936931.4\n", + " wavelet-HLL_Kurtosis : 5.09932613055\n", " wavelet-HLL_RobustMeanAbsoluteDeviation : 22.7497539081\n", " wavelet-HLL_Mean : -5.07735424173\n", - " wavelet-LHH_RootMeanSquared : 1999.33891946\n", - " wavelet-LHH_Energy : 16537062247.2\n", - " wavelet-LHH_Uniformity : 0.140809788318\n", - " wavelet-LHH_Maximum : 279.350380756\n", + " wavelet-HLL_Variance : 2328.11665966\n", + " wavelet-HLL_Uniformity : 0.163587425574\n", + " wavelet-HLL_Energy : 16473718010.5\n", + " wavelet-LLL_Range : 1712.56194574\n", + " wavelet-LLL_MeanAbsoluteDeviation : 293.143995944\n", + " wavelet-LLL_10Percentile : 1812.68473489\n", + " wavelet-LLL_Skewness : 0.228846426465\n", + " wavelet-LLL_InterquartileRange : 550.594267427\n", + " wavelet-LLL_90Percentile : 2739.69052111\n", + " wavelet-LLL_Maximum : 3180.63918677\n", + " wavelet-LLL_RootMeanSquared : 4269.54365408\n", + " wavelet-LLL_Median : 2244.88673609\n", + " wavelet-LLL_StandardDeviation : 350.172190209\n", + " wavelet-LLL_Entropy : 5.78300489052\n", + " wavelet-LLL_Minimum : 1468.07724103\n", + " wavelet-LLL_TotalEnergy : 299186404755.0\n", + " wavelet-LLL_Kurtosis : 2.27365643067\n", + " wavelet-LLL_RobustMeanAbsoluteDeviation : 220.739697172\n", + " wavelet-LLL_Mean : 2255.1595095\n", + " wavelet-LLL_Variance : 122620.562796\n", + " wavelet-LLL_Uniformity : 0.0199077767278\n", + " wavelet-LLL_Energy : 75413385469.3\n", + " wavelet-HHL_Range : 197.650791431\n", + " wavelet-HHL_MeanAbsoluteDeviation : 14.4086961805\n", + " wavelet-HHL_10Percentile : -22.0062020433\n", + " wavelet-HHL_Skewness : 0.121890250304\n", + " wavelet-HHL_InterquartileRange : 22.3805938159\n", + " wavelet-HHL_90Percentile : 23.0361222477\n", + " wavelet-HHL_Maximum : 96.9275598214\n", + " wavelet-HHL_RootMeanSquared : 2000.43345645\n", + " wavelet-HHL_Median : 0.0829386441652\n", + " wavelet-HHL_StandardDeviation : 19.2752766031\n", + " wavelet-HHL_Entropy : 1.75422760497\n", + " wavelet-HHL_Minimum : -100.72323161\n", + " wavelet-HHL_TotalEnergy : 65679094540.6\n", + " wavelet-HHL_Kurtosis : 4.71302154772\n", + " wavelet-HHL_RobustMeanAbsoluteDeviation : 9.30098915932\n", + " wavelet-HHL_Mean : 0.340590352112\n", + " wavelet-HHL_Variance : 371.536288126\n", + " wavelet-HHL_Uniformity : 0.358701481744\n", + " wavelet-HHL_Energy : 16555173614.7\n", " wavelet-LHH_Range : 604.053834439\n", - " wavelet-LHH_Skewness : 0.197382131363\n", - " wavelet-LHH_Kurtosis : 5.10438678184\n", - " wavelet-LHH_Median : -1.94009209997\n", - " wavelet-LHH_Variance : 3189.24714715\n", + " wavelet-LHH_MeanAbsoluteDeviation : 41.6368845931\n", " wavelet-LHH_10Percentile : -69.1252699081\n", - " wavelet-LHH_Entropy : 3.17918664471\n", - " wavelet-LHH_TotalEnergy : 65607241581.1\n", + " wavelet-LHH_Skewness : 0.197382131363\n", " wavelet-LHH_InterquartileRange : 61.7174514323\n", - " wavelet-LHH_MeanAbsoluteDeviation : 41.6368845931\n", - " wavelet-LHH_StandardDeviation : 56.4734198287\n", " wavelet-LHH_90Percentile : 63.2151706827\n", + " wavelet-LHH_Maximum : 279.350380756\n", + " wavelet-LHH_RootMeanSquared : 1999.33891946\n", + " wavelet-LHH_Median : -1.94009209997\n", + " wavelet-LHH_StandardDeviation : 56.4734198287\n", + " wavelet-LHH_Entropy : 3.17918664471\n", " wavelet-LHH_Minimum : -324.703453682\n", + " wavelet-LHH_TotalEnergy : 65607241581.1\n", + " wavelet-LHH_Kurtosis : 5.10438678184\n", " wavelet-LHH_RobustMeanAbsoluteDeviation : 26.4723285429\n", " wavelet-LHH_Mean : -1.45881510799\n", - " wavelet-LHL_RootMeanSquared : 1995.91519044\n", - " wavelet-LHL_Energy : 16480473600.0\n", - " wavelet-LHL_Uniformity : 0.121366697967\n", - " wavelet-LHL_Maximum : 286.571219987\n", + " wavelet-LHH_Variance : 3189.24714715\n", + " wavelet-LHH_Uniformity : 0.140809788318\n", + " wavelet-LHH_Energy : 16537062247.2\n", + " wavelet-HHH_Range : 151.165663688\n", + " wavelet-HHH_MeanAbsoluteDeviation : 13.0759756862\n", + " wavelet-HHH_10Percentile : -21.0383130256\n", + " wavelet-HHH_Skewness : -0.0688112737237\n", + " wavelet-HHH_InterquartileRange : 20.3192746422\n", + " wavelet-HHH_90Percentile : 20.9238433344\n", + " wavelet-HHH_Maximum : 76.4099650187\n", + " wavelet-HHH_RootMeanSquared : 2000.23985683\n", + " wavelet-HHH_Median : 0.109117292789\n", + " wavelet-HHH_StandardDeviation : 17.3191286736\n", + " wavelet-HHH_Entropy : 1.62781167475\n", + " wavelet-HHH_Minimum : -74.7556986689\n", + " wavelet-HHH_TotalEnergy : 65666382462.8\n", + " wavelet-HHH_Kurtosis : 4.32455549814\n", + " wavelet-HHH_RobustMeanAbsoluteDeviation : 8.53027450692\n", + " wavelet-HHH_Mean : 0.164876359429\n", + " wavelet-HHH_Variance : 299.952218013\n", + " wavelet-HHH_Uniformity : 0.382919979814\n", + " wavelet-HHH_Energy : 16551969388.8\n", " wavelet-LHL_Range : 641.465953025\n", - " wavelet-LHL_Skewness : -0.369538595422\n", - " wavelet-LHL_Kurtosis : 4.82046635261\n", - " wavelet-LHL_Median : -4.09721168383\n", - " wavelet-LHL_Variance : 4432.09816024\n", + " wavelet-LHL_MeanAbsoluteDeviation : 48.9628822529\n", " wavelet-LHL_10Percentile : -85.6408963111\n", - " wavelet-LHL_Entropy : 3.40407739189\n", - " wavelet-LHL_TotalEnergy : 65382738281.1\n", + " wavelet-LHL_Skewness : -0.369538595422\n", " wavelet-LHL_InterquartileRange : 71.4997770702\n", - " wavelet-LHL_MeanAbsoluteDeviation : 48.9628822529\n", - " wavelet-LHL_StandardDeviation : 66.5740051389\n", " wavelet-LHL_90Percentile : 71.5796532291\n", + " wavelet-LHL_Maximum : 286.571219987\n", + " wavelet-LHL_RootMeanSquared : 1995.91519044\n", + " wavelet-LHL_Median : -4.09721168383\n", + " wavelet-LHL_StandardDeviation : 66.5740051389\n", + " wavelet-LHL_Entropy : 3.40407739189\n", " wavelet-LHL_Minimum : -354.894733038\n", + " wavelet-LHL_TotalEnergy : 65382738281.1\n", + " wavelet-LHL_Kurtosis : 4.82046635261\n", " wavelet-LHL_RobustMeanAbsoluteDeviation : 30.6452121553\n", " wavelet-LHL_Mean : -5.19541075848\n", - " wavelet-HHL_RootMeanSquared : 2000.43345645\n", - " wavelet-HHL_Energy : 16555173614.7\n", - " wavelet-HHL_Uniformity : 0.358701481744\n", - " wavelet-HHL_Maximum : 96.9275598214\n", - " wavelet-HHL_Range : 197.650791431\n", - " wavelet-HHL_Skewness : 0.121890250304\n", - " wavelet-HHL_Kurtosis : 4.71302154772\n", - " wavelet-HHL_Median : 0.0829386441652\n", - " wavelet-HHL_Variance : 371.536288126\n", - " wavelet-HHL_10Percentile : -22.0062020433\n", - " wavelet-HHL_Entropy : 1.75422760497\n", - " wavelet-HHL_TotalEnergy : 65679094540.6\n", - " wavelet-HHL_InterquartileRange : 22.3805938159\n", - " wavelet-HHL_MeanAbsoluteDeviation : 14.4086961805\n", - " wavelet-HHL_StandardDeviation : 19.2752766031\n", - " wavelet-HHL_90Percentile : 23.0361222477\n", - " wavelet-HHL_Minimum : -100.72323161\n", - " wavelet-HHL_RobustMeanAbsoluteDeviation : 9.30098915932\n", - " wavelet-HHL_Mean : 0.340590352112\n", - " wavelet-LLH_RootMeanSquared : 2025.7276121\n", - " wavelet-LLH_Energy : 16976478846.8\n", - " wavelet-LLH_Uniformity : 0.0304399667913\n", - " wavelet-LLH_Maximum : 733.850508276\n", - " wavelet-LLH_Range : 1516.85940092\n", - " wavelet-LLH_Skewness : -0.525773815287\n", - " wavelet-LLH_Kurtosis : 2.69674899921\n", - " wavelet-LLH_Median : 62.7368130339\n", - " wavelet-LLH_Variance : 63709.1700017\n", - " wavelet-LLH_10Percentile : -370.145218742\n", - " wavelet-LLH_Entropy : 5.27888924024\n", - " wavelet-LLH_TotalEnergy : 67350532534.4\n", - " wavelet-LLH_InterquartileRange : 352.67245821\n", - " wavelet-LLH_MeanAbsoluteDeviation : 205.422769392\n", - " wavelet-LLH_StandardDeviation : 252.406755064\n", - " wavelet-LLH_90Percentile : 297.911610403\n", - " wavelet-LLH_Minimum : -783.008892644\n", - " wavelet-LLH_RobustMeanAbsoluteDeviation : 146.79059076\n", - " wavelet-LLH_Mean : 9.94109078503\n", - " wavelet-LLL_RootMeanSquared : 4269.54365408\n", - " wavelet-LLL_Energy : 75413385469.3\n", - " wavelet-LLL_Uniformity : 0.0199077767278\n", - " wavelet-LLL_Maximum : 3180.63918677\n", - " wavelet-LLL_Range : 1712.56194574\n", - " wavelet-LLL_Skewness : 0.228846426465\n", - " wavelet-LLL_Kurtosis : 2.27365643067\n", - " wavelet-LLL_Median : 2244.88673609\n", - " wavelet-LLL_Variance : 122620.562796\n", - " wavelet-LLL_10Percentile : 1812.68473489\n", - " wavelet-LLL_Entropy : 5.78300489052\n", - " wavelet-LLL_TotalEnergy : 299186404755.0\n", - " wavelet-LLL_InterquartileRange : 550.594267427\n", - " wavelet-LLL_MeanAbsoluteDeviation : 293.143995944\n", - " wavelet-LLL_StandardDeviation : 350.172190209\n", - " wavelet-LLL_90Percentile : 2739.69052111\n", - " wavelet-LLL_Minimum : 1468.07724103\n", - " wavelet-LLL_RobustMeanAbsoluteDeviation : 220.739697172\n", - " wavelet-LLL_Mean : 2255.1595095\n", - " wavelet-HHH_RootMeanSquared : 2000.23985683\n", - " wavelet-HHH_Energy : 16551969388.8\n", - " wavelet-HHH_Uniformity : 0.382919979814\n", - " wavelet-HHH_Maximum : 76.4099650187\n", - " wavelet-HHH_Range : 151.165663688\n", - " wavelet-HHH_Skewness : -0.0688112737237\n", - " wavelet-HHH_Kurtosis : 4.32455549814\n", - " wavelet-HHH_Median : 0.109117292789\n", - " wavelet-HHH_Variance : 299.952218013\n", - " wavelet-HHH_10Percentile : -21.0383130256\n", - " wavelet-HHH_Entropy : 1.62781167475\n", - " wavelet-HHH_TotalEnergy : 65666382462.8\n", - " wavelet-HHH_InterquartileRange : 20.3192746422\n", - " wavelet-HHH_MeanAbsoluteDeviation : 13.0759756862\n", - " wavelet-HHH_StandardDeviation : 17.3191286736\n", - " wavelet-HHH_90Percentile : 20.9238433344\n", - " wavelet-HHH_Minimum : -74.7556986689\n", - " wavelet-HHH_RobustMeanAbsoluteDeviation : 8.53027450692\n", - " wavelet-HHH_Mean : 0.164876359429\n" + " wavelet-LHL_Variance : 4432.09816024\n", + " wavelet-LHL_Uniformity : 0.121366697967\n", + " wavelet-LHL_Energy : 16480473600.0\n" ] } ], @@ -1404,23 +1368,14 @@ " waveletFeatureName = '%s_%s' % (str(decompositionName), key)\n", " print(' ', waveletFeatureName, ':', val)" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { - "display_name": "Python [conda root]", + "display_name": "Python 3", "language": "python", - "name": "conda-root-py" + "name": "python3" }, "language_info": { "codemirror_mode": { diff --git a/bin/Notebooks/helloRadiomics.ipynb b/bin/Notebooks/helloRadiomics.ipynb index 964d4be7..5484f33c 100644 --- a/bin/Notebooks/helloRadiomics.ipynb +++ b/bin/Notebooks/helloRadiomics.ipynb @@ -423,33 +423,33 @@ "Calculating features\n", "\t\tComputing firstorder\n", "Computed general_info_BoundingBox: (162; 84; 11; 47; 70; 7)\n", - "Computed general_info_GeneralSettings: {'label': 1; 'binWidth': 25; 'padDistance': 5; 'interpolator': 'sitkBSpline'; 'resampledPixelSpacing': None; 'verbose': True}\n", + "Computed general_info_GeneralSettings: {'verbose': True; 'label': 1; 'resampledPixelSpacing': None; 'binWidth': 25; 'interpolator': 'sitkBSpline'; 'padDistance': 5}\n", "Computed general_info_ImageHash: 5c9ce3ca174f0f8324aa4d277e0fef82dc5ac566\n", "Computed general_info_ImageSpacing: (0.7812499999999999; 0.7812499999999999; 6.499999999999998)\n", "Computed general_info_InputImages: {'Original': {}}\n", "Computed general_info_MaskHash: 9dc2c3137b31fd872997d92c9a92d5178126d9d3\n", - "Computed general_info_Version: v1.0.1.post5.dev0+g72ac3cb\n", + "Computed general_info_Version: v1.0.1.post6.dev0+g5b1e8bb\n", "Computed general_info_VolumeNum: 2\n", "Computed general_info_VoxelNum: 4137\n", - "Computed original_firstorder_Median: 812.0\n", - "Computed original_firstorder_RobustMeanAbsoluteDeviation: 103.00138343\n", - "Computed original_firstorder_Skewness: 0.275650859086\n", - "Computed original_firstorder_InterquartileRange: 253.0\n", - "Computed original_firstorder_Maximum: 1266.0\n", + "Computed original_firstorder_Kurtosis: 2.18077293939\n", "Computed original_firstorder_StandardDeviation: 156.611235894\n", + "Computed original_firstorder_10Percentile: 632.0\n", + "Computed original_firstorder_90Percentile: 1044.4\n", "Computed original_firstorder_Minimum: 468.0\n", - "Computed original_firstorder_RootMeanSquared: 2829.57282108\n", + "Computed original_firstorder_RobustMeanAbsoluteDeviation: 103.00138343\n", "Computed original_firstorder_Range: 798.0\n", - "Computed original_firstorder_Kurtosis: 2.18077293939\n", - "Computed original_firstorder_90Percentile: 1044.4\n", - "Computed original_firstorder_MeanAbsoluteDeviation: 133.447261953\n", - "Computed original_firstorder_TotalEnergy: 131407662126.0\n", - "Computed original_firstorder_10Percentile: 632.0\n", - "Computed original_firstorder_Mean: 825.235436307\n", + "Computed original_firstorder_Maximum: 1266.0\n", "Computed original_firstorder_Uniformity: 0.0451569635559\n", - "Computed original_firstorder_Energy: 33122817481.0\n", + "Computed original_firstorder_Mean: 825.235436307\n", + "Computed original_firstorder_TotalEnergy: 131407662126.0\n", + "Computed original_firstorder_MeanAbsoluteDeviation: 133.447261953\n", + "Computed original_firstorder_RootMeanSquared: 2829.57282108\n", + "Computed original_firstorder_InterquartileRange: 253.0\n", + "Computed original_firstorder_Entropy: 4.6019355539\n", "Computed original_firstorder_Variance: 24527.0792084\n", - "Computed original_firstorder_Entropy: 4.6019355539\n" + "Computed original_firstorder_Energy: 33122817481.0\n", + "Computed original_firstorder_Skewness: 0.275650859086\n", + "Computed original_firstorder_Median: 812.0\n" ] } ], @@ -465,9 +465,9 @@ "metadata": { "anaconda-cloud": {}, "kernelspec": { - "display_name": "Python [conda root]", + "display_name": "Python 3", "language": "python", - "name": "conda-root-py" + "name": "python3" }, "language_info": { "codemirror_mode": { diff --git a/bin/addClassToBaseline.py b/bin/addClassToBaseline.py index 2c9b0b33..92939803 100644 --- a/bin/addClassToBaseline.py +++ b/bin/addClassToBaseline.py @@ -34,17 +34,17 @@ def main(): if len(testCases) > 0: break if len(testCases) == 0: - print ("No baselinefiles containing testcases found, exiting...") + print("No baselinefiles containing testcases found, exiting...") exit(-1) newClasses = [cls for cls in featureClasses if not os.path.exists(os.path.join(baselineDir, 'baseline_%s.csv' % (cls)))] if len(newClasses) == 0: - print "No new classes to add, exiting..." + print("No new classes to add, exiting...") exit(0) - print "Adding new classes: ", newClasses + print("Adding new classes: ", newClasses) newBaseline = {} @@ -59,21 +59,21 @@ def main(): for cls in newClasses: newBaseline[cls] = {} - print "Computing new baseline" + print("Computing new baseline") for testCase in testCases: - print "\tCalculating test case", testCase + print("\tCalculating test case", testCase) imagePath = os.path.join(dataDir, testCase + '_image.nrrd') maskPath = os.path.join(dataDir, testCase + '_label.nrrd') image, mask = extractor.loadImage(imagePath, maskPath) if image is None or mask is None: - print "Error during loading of image/mask, testcase:", testCase + print("Error during loading of image/mask, testcase:", testCase) continue # testImage or mask not found / error during loading provenance = extractor.getProvenance(imagePath, maskPath, mask) image, mask, bb = imageoperations.cropToTumorMask(image, mask) for cls in newClasses: - print "\t\tCalculating class", cls + print("\t\tCalculating class", cls) newBaseline[cls][testCase] = collections.OrderedDict() newBaseline[cls][testCase]["Patient ID"] = testCase newBaseline[cls][testCase].update(provenance) @@ -82,7 +82,7 @@ def main(): featureClass.calculateFeatures() newBaseline[cls][testCase].update(featureClass.featureValues) - print "Writing new baseline" + print("Writing new baseline") for cls in newClasses: baselineFile = os.path.join(baselineDir, 'baseline_%s.csv' % (cls)) with open(baselineFile, 'wb') as baseline: diff --git a/bin/batchExamples/DatasetHierarchyReader.py b/bin/batchExamples/DatasetHierarchyReader.py index 88bc521b..dba4063d 100644 --- a/bin/batchExamples/DatasetHierarchyReader.py +++ b/bin/batchExamples/DatasetHierarchyReader.py @@ -52,7 +52,7 @@ def readReconstructionsDirectory(self, studyDirectory, subfolders, create=False) recDirectory = os.path.join(studyDirectory, "Reconstructions") if not os.path.exists(recDirectory): os.mkdir(recDirectory) - print "\tCreated:", recDirectory + print("\tCreated:", recDirectory) return recDirectory, images @@ -67,7 +67,7 @@ def readSegmentationsDirectory(self, studyDirectory, subfolders, create=False): segDirectory = os.path.join(studyDirectory, "Segmentations") if not os.path.exists(segDirectory): os.mkdir(segDirectory) - print "\tCreated:", segDirectory + print("\tCreated:", segDirectory) return segDirectory, labels @@ -82,7 +82,7 @@ def readResourcesDirectory(self, studyDirectory, subfolders, create=False): resDirectory = os.path.join(studyDirectory, "Resources") if not os.path.exists(resDirectory): os.mkdir(resDirectory) - print "\tCreated:", resDirectory + print("\tCreated:", resDirectory) return resDirectory, resources @@ -117,14 +117,14 @@ def findImageAndLabelPair(self, imageFilepaths, maskFilepaths, keywordSettings): matchedMasks.append(maskFilepath) if len(matchedImages) < 1: - print "ERROR: No Images Matched" + print("ERROR: No Images Matched") elif len(matchedImages) > 1: - print "ERROR: Multiple Images Matched" + print("ERROR: Multiple Images Matched") if len(matchedMasks) < 1: - print "ERROR: No Masks Matched" + print("ERROR: No Masks Matched") elif len(matchedMasks) > 1: - print "ERROR: Multiple Masks Matched" + print("ERROR: Multiple Masks Matched") if (len(matchedImages) == 1) and (len(matchedMasks) == 1): return matchedImages[0], matchedMasks[0] diff --git a/bin/batchExamples/GenerateInputCSV_Datasethierarchy.py b/bin/batchExamples/GenerateInputCSV_Datasethierarchy.py index dd43c10c..257706e1 100644 --- a/bin/batchExamples/GenerateInputCSV_Datasethierarchy.py +++ b/bin/batchExamples/GenerateInputCSV_Datasethierarchy.py @@ -1,7 +1,7 @@ from __future__ import print_function, unicode_literals, division, absolute_import import os import csv -from DatasetHierarchyReader import DatasetHierarchyReader +from .DatasetHierarchyReader import DatasetHierarchyReader def main(): diff --git a/bin/batchExamples/batchprocessing.py b/bin/batchExamples/batchprocessing.py index 3483d7b7..a47ed776 100644 --- a/bin/batchExamples/batchprocessing.py +++ b/bin/batchExamples/batchprocessing.py @@ -33,7 +33,7 @@ def main(): radiomics.logger.handlers[0].setLevel(logging.WARNING) logging.info('Loading CSV') - print "Loading CSV" + print("Loading CSV") flists = [] try: @@ -43,8 +43,8 @@ def main(): except Exception: logging.error('CSV READ FAILED:\n%s', traceback.format_exc()) - print "Loading Done" - print ("Patients: " + str(len(flists))) + print("Loading Done") + print("Patients: " + str(len(flists))) kwargs = {} kwargs['binWidth'] = 25 @@ -60,7 +60,7 @@ def main(): # extractor.enableInputImages(wavelet= {'level': 2}) for idx, entry in enumerate(flists, start=1): - print "(%d/%d) Processing Patient: %s, Study: %s, Reader: %s" % (idx, len(flists), entry[0], entry[1], entry[2]) + print("(%d/%d) Processing Patient: %s, Study: %s, Reader: %s" % (idx, len(flists), entry[0], entry[1], entry[2])) logging.info("(%d/%d) Processing Patient: %s, Study: %s, Reader: %s", idx, len(flists), entry[0], entry[1], entry[2]) diff --git a/bin/helloFeatureClass.py b/bin/helloFeatureClass.py index 8b8604f1..931fee35 100644 --- a/bin/helloFeatureClass.py +++ b/bin/helloFeatureClass.py @@ -50,7 +50,7 @@ firstOrderFeatures.enableFeatureByName('Mean', True) # firstOrderFeatures.enableAllFeatures() -print 'Will calculate the following first order features: ' +print('Will calculate the following first order features: ') for f in firstOrderFeatures.enabledFeatures.keys(): print(' ', f) print(eval('firstOrderFeatures.get' + f + 'FeatureValue.__doc__')) @@ -61,7 +61,7 @@ print('Calculated first order features: ') for (key, val) in firstOrderFeatures.featureValues.items(): - print ' ', key, ':', val + print(' ', key, ':', val) # # Show Shape features diff --git a/bin/helloRadiomics.py b/bin/helloRadiomics.py index 74c0ae67..079362ae 100644 --- a/bin/helloRadiomics.py +++ b/bin/helloRadiomics.py @@ -10,10 +10,10 @@ maskName = os.path.join(dataDir, testCase + '_label.nrrd') if not os.path.exists(imageName): - print 'Error: problem finding input image', imageName + print('Error: problem finding input image', imageName) exit() if not os.path.exists(maskName): - print 'Error: problem finding input labelmap', maskName + print('Error: problem finding input labelmap', maskName) exit() # Define settings for signature calculation @@ -53,16 +53,16 @@ handler.setFormatter(formatter) logger.addHandler(handler) -print "Active features:" +print("Active features:") for cls, features in extractor.enabledFeatures.items(): if len(features) == 0: features = extractor.getFeatureNames(cls) for f in features: - print f - print eval('extractor.featureClasses["%s"].get%sFeatureValue.__doc__' % (cls, f)) + print(f) + print(eval('extractor.featureClasses["%s"].get%sFeatureValue.__doc__' % (cls, f))) -print "Calculating features" +print("Calculating features") featureVector = extractor.execute(imageName, maskName) for featureName in featureVector.keys(): - print "Computed %s: %s" % (featureName, featureVector[featureName]) + print("Computed %s: %s" % (featureName, featureVector[featureName])) diff --git a/radiomics/shape.py b/radiomics/shape.py index c913d68e..8ca1854e 100644 --- a/radiomics/shape.py +++ b/radiomics/shape.py @@ -119,7 +119,7 @@ def _calculateSurfaceArea(self): def _getMaximum2Ddiameter(self, dim): otherDims = tuple(set([0, 1, 2]) - set([dim])) - a = numpy.array(zip(*self.matrixCoordinates)) + a = numpy.array(list(zip(*self.matrixCoordinates))) maxDiameter = 0 # Check maximum diameter in every slice, retain the overall maximum diff --git a/tests/test_docstrings.py b/tests/test_docstrings.py index 60bd82be..978038bf 100644 --- a/tests/test_docstrings.py +++ b/tests/test_docstrings.py @@ -3,7 +3,7 @@ # nosetests --nocapture -v tests/test_docstrings.py from radiomics.featureextractor import RadiomicsFeaturesExtractor -from testUtils import custom_name_func +from .testUtils import custom_name_func import logging from nose_parameterized import parameterized diff --git a/tests/test_features.py b/tests/test_features.py index f8678439..2f2e312c 100644 --- a/tests/test_features.py +++ b/tests/test_features.py @@ -4,7 +4,7 @@ from __future__ import print_function, unicode_literals, division from radiomics.featureextractor import RadiomicsFeaturesExtractor -from testUtils import RadiomicsTestUtils, custom_name_func +from .testUtils import RadiomicsTestUtils, custom_name_func import os import logging from nose_parameterized import parameterized From 72649ec17ff9d2ed77f4d2d05b35d4d942b7ab06 Mon Sep 17 00:00:00 2001 From: Joost van Griethuysen Date: Mon, 13 Feb 2017 09:42:06 +0100 Subject: [PATCH 4/6] BUG: Revert to using absolute import within tests modules --- tests/test_docstrings.py | 2 +- tests/test_features.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_docstrings.py b/tests/test_docstrings.py index 978038bf..60bd82be 100644 --- a/tests/test_docstrings.py +++ b/tests/test_docstrings.py @@ -3,7 +3,7 @@ # nosetests --nocapture -v tests/test_docstrings.py from radiomics.featureextractor import RadiomicsFeaturesExtractor -from .testUtils import custom_name_func +from testUtils import custom_name_func import logging from nose_parameterized import parameterized diff --git a/tests/test_features.py b/tests/test_features.py index 2f2e312c..f8678439 100644 --- a/tests/test_features.py +++ b/tests/test_features.py @@ -4,7 +4,7 @@ from __future__ import print_function, unicode_literals, division from radiomics.featureextractor import RadiomicsFeaturesExtractor -from .testUtils import RadiomicsTestUtils, custom_name_func +from testUtils import RadiomicsTestUtils, custom_name_func import os import logging from nose_parameterized import parameterized From d083a0060779c81f498200fea7c75e66f3b22186 Mon Sep 17 00:00:00 2001 From: Joost van Griethuysen Date: Mon, 13 Feb 2017 14:48:58 +0100 Subject: [PATCH 5/6] BUG: Fix python 3.5 unicode errors. Some functions expect string types (such as in nose-testing), but python 3.5 by default provides unicode strings. Add forced casts where necessary. Also, 'wb' mode requires strings to be encoded as bytes, not string in python 3.5. The fix did not work in this case. Change mode to 'w', which accepts regular strings. Additionally, safe_cmp produced errors for dictionary comparison in python 3.5, replace by `==` comparison. Finally, update layout in testing files (such as replace `!=` by `is not` in comparisons to `None`). Update feature name in testing output to also reflect the feature class. --- radiomics/__init__.py | 4 +-- tests/testUtils.py | 42 +++++++++++------------ tests/test_docstrings.py | 74 +++++++++++++++++++++------------------- tests/test_features.py | 6 ++-- 4 files changed, 61 insertions(+), 65 deletions(-) diff --git a/radiomics/__init__.py b/radiomics/__init__.py index e4503fc9..68435361 100644 --- a/radiomics/__init__.py +++ b/radiomics/__init__.py @@ -7,12 +7,10 @@ if in_py3: c_str_type = str - safe_xrange = lambda *x,**kwargs: iter(range(*x, **kwargs)) - safe_cmp = lambda a,b: (a>b)-(a3}, param.args = %s'.format(param_num), testcase_func.__name__, param.args) - return "%s_%s" % ( + return str("%s_%s" % ( testcase_func.__name__, parameterized.to_safe_name("_".join(str(x) for x in param.args)), - ) + )) class RadiomicsTestUtils: @@ -50,6 +51,7 @@ class RadiomicsTestUtils: It provides utility methods to get the baseline feature value for a feature class and compare it to the result generated by the test. """ + def __init__(self): global logger @@ -105,14 +107,14 @@ class or test case is changed, function returns True. self._featureClassName = className # Check if test settings have changed - if safe_cmp(self._kwargs, self.getBaselineDict(className, testCase)) != 0: + if self._kwargs != self.getBaselineDict(className, testCase): self._kwargs = self.getBaselineDict(className, testCase) self._testCase = None # forces image to be reloaded (as settings have changed) # Next, set testCase if necessary if self._testCase != testCase: - imageName = os.path.join(self._dataDir, testCase + '_image.nrrd') - maskName = os.path.join(self._dataDir, testCase + '_label.nrrd') + imageName = str(os.path.join(self._dataDir, testCase + '_image.nrrd')) + maskName = str(os.path.join(self._dataDir, testCase + '_label.nrrd')) self._logger.info("Reading the image and mask for test case %s", testCase) self._image = sitk.ReadImage(imageName) @@ -188,21 +190,21 @@ def checkResult(self, featureName, value): """ Use utility methods to get and test the results against the expected baseline value for this key. """ - + longName = '%s_%s' % (self._featureClassName, featureName) if value is None: - self._diffs[self._testCase][featureName] = None - self._results[self._testCase][featureName] = None - assert (value != None) + self._diffs[self._testCase][longName] = None + self._results[self._testCase][longName] = None + assert (value is not None) if math.isnan(value): - self._diffs[self._testCase][featureName] = numpy.nan - self._results[self._testCase][featureName] = numpy.nan + self._diffs[self._testCase][longName] = numpy.nan + self._results[self._testCase][longName] = numpy.nan assert (not math.isnan(value)) # save the result using the baseline class and feature names self._logger.debug('checkResults: featureName = %s', featureName) - self._results[self._testCase][featureName] = value + self._results[self._testCase][longName] = value assert featureName in self._baseline[self._featureClassName][self._testCase] baselineValue = float(self._baseline[self._featureClassName][self._testCase][featureName]) @@ -218,7 +220,7 @@ def checkResult(self, featureName, value): percentDiff = abs(1.0 - (value / baselineValue)) # save the difference - self._diffs[self._testCase][featureName] = percentDiff + self._diffs[self._testCase][longName] = percentDiff # check for a less than three percent difference if (percentDiff >= 0.03): @@ -242,24 +244,18 @@ def writeCSV(self, data, fileName): {'id1' : {'f1':n1, 'f2':n2}, 'id2' : {'f1':n3, 'f2':n4}} """ - csvFile = open(fileName, 'wb') + csvFile = open(fileName, 'w') csvFileWriter = csv.writer(csvFile) # get the headers from the first row - header = sorted(data[list(data.keys())[0]].keys()) + header = list(data[list(data.keys())[0]].keys()) header = ['testCase'] + header - if in_py3: - # since csvWriter only supports bytes not str - header = [c_col.encode('ascii') for c_col in header] csvFileWriter.writerow(header) for testCase in sorted(data.keys()): thisCase = data[testCase] thisCase['testCase'] = testCase row = [] for h in header: - row = row + [thisCase[h]] - if in_py3: - # since csvWriter only supports bytes not str - row = [c_col.encode('ascii') for c_col in row] + row = row + [thisCase.get(h, "N/A")] csvFileWriter.writerow(row) csvFile.close() self._logger.info('Wrote to file %s', fileName) diff --git a/tests/test_docstrings.py b/tests/test_docstrings.py index 60bd82be..d9cf893c 100644 --- a/tests/test_docstrings.py +++ b/tests/test_docstrings.py @@ -9,42 +9,44 @@ featureClasses = RadiomicsFeaturesExtractor.getFeatureClasses() + def setup_module(module): - # runs before anything in this file - print ("") # this is to get a newline after the dots - return + # runs before anything in this file + print("") # this is to get a newline after the dots + return + class TestDocStrings: - def setup(self): - # setup before each test method - print ("") # this is to get a newline after the dots - - @classmethod - def setup_class(self): - # called before any methods in this class - print ("") # this is to get a newline after the dots - - @classmethod - def teardown_class(self): - # run after any methods in this class - print ("") # this is to get a newline after the dots - - def generate_scenarios(): - global featureClasses - for featureClassName, featureClass in featureClasses.items(): - logging.info('generate_scenarios %s', featureClassName) - doc = featureClass.__doc__ - assert(doc != None) - - featureNames = featureClass.getFeatureNames() - for f in featureNames: - yield (featureClassName, f) - - @parameterized.expand(generate_scenarios(), testcase_func_name=custom_name_func) - def test_class(self, featureClassName, featureName): - global featureClasses - logging.info('%s', featureName) - features = featureClasses[featureClassName] - doc = eval('features.get'+featureName+'FeatureValue.__doc__') - logging.info('%s', doc) - assert(doc != None) + def setup(self): + # setup before each test method + print("") # this is to get a newline after the dots + + @classmethod + def setup_class(self): + # called before any methods in this class + print("") # this is to get a newline after the dots + + @classmethod + def teardown_class(self): + # run after any methods in this class + print("") # this is to get a newline after the dots + + def generate_scenarios(): + global featureClasses + for featureClassName, featureClass in featureClasses.items(): + logging.info('generate_scenarios %s', featureClassName) + doc = featureClass.__doc__ + assert (doc is not None) + + featureNames = featureClass.getFeatureNames() + for f in featureNames: + yield (featureClassName, f) + + @parameterized.expand(generate_scenarios(), testcase_func_name=custom_name_func) + def test_class(self, featureClassName, featureName): + global featureClasses + logging.info('%s', featureName) + features = featureClasses[featureClassName] + doc = eval('features.get' + featureName + 'FeatureValue.__doc__') + logging.info('%s', doc) + assert (doc is not None) diff --git a/tests/test_features.py b/tests/test_features.py index f8678439..3050c126 100644 --- a/tests/test_features.py +++ b/tests/test_features.py @@ -27,7 +27,7 @@ def generate_scenarios(): for testCase in testCases: for featureClassName in featureClassNames: featureNames = extractor.featureClasses[featureClassName].getFeatureNames() - assert (featureNames != None) + assert (featureNames is not None) assert (len(featureNames) > 0) logging.debug('generate_scenarios: featureNames = %s', featureNames) for featureName in featureNames: @@ -53,7 +53,7 @@ def test_scenario(self, testCase, featureClassName, featureName): logging.debug('Init %s' % (featureClassName)) featureClass = extractor.featureClasses[featureClassName](testImage, testMask, **testUtils.getKwargs()) - assert featureClass != None + assert featureClass is not None featureClass.disableAllFeatures() featureClass.enableFeatureByName(featureName) @@ -76,5 +76,5 @@ def teardown_module(): diffFile = os.path.join(testUtils.getDataDir(), 'Baseline2PyradiomicsFeaturesDiff.csv') testUtils.writeCSV(diff, diffFile) logging.info( - "Wrote calculated features to %s, and the differences between the matlab features and the pyradiomics ones to %s.", + "Wrote calculated features to %s, and the differences between the baseline features and the calculated ones to %s.", resultsFile, diffFile) From ac07f3f425dd6403b7aa856ec8c263618c6ed543 Mon Sep 17 00:00:00 2001 From: Joost van Griethuysen Date: Mon, 13 Feb 2017 14:52:55 +0100 Subject: [PATCH 6/6] BUG: Fix iteration error in GLRLM In python 3.5 GLRLM results differed from baseline. This due to the different implementation of the `filter()` function, which returns an iterator instead of a list. In GLRLM calculation, there where 2 iterations over this iter-object (one for flat-angle check, one for matrix calculation), causing it to break in python 3.5. Fix by merging the 2 iterations into one loop. Additionally, simplify the filter function. --- radiomics/glrlm.py | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/radiomics/glrlm.py b/radiomics/glrlm.py index 9a99f7c7..b3380dd9 100644 --- a/radiomics/glrlm.py +++ b/radiomics/glrlm.py @@ -128,8 +128,7 @@ def _calculateGLRLM(self): for a in safe_xrange(-self.matrix.shape[0] + 1, self.matrix.shape[1])]: diags.extend([h.diagonal(b, 0, 1) for b in safe_xrange(-h.shape[0] + 1, h.shape[1])]) - matrixDiagonals.append(filter(lambda diag: numpy.nonzero(diag != padVal)[0].size > 0, diags)) - + matrixDiagonals.append(filter(lambda diag: numpy.any(diag != padVal), diags)) P_glrlm = numpy.zeros((Ng, Nr, int(len(matrixDiagonals)))) # Run-Length Encoding (rle) for the list of diagonals @@ -138,18 +137,17 @@ def _calculateGLRLM(self): P = P_glrlm[:, :, angle_idx] # Check whether delineation is 2D for current angle (all diagonals contain 0 or 1 non-pad value) isMultiElement = False - for d in angle: - if numpy.where(d != padVal)[0].shape[0] > 1: + for diagonal in angle: + if not isMultiElement and numpy.sum(diagonal != padVal) > 1: isMultiElement = True - break - if isMultiElement: - for diagonal in angle: - pos, = numpy.where(numpy.diff(diagonal) != 0) - pos = numpy.concatenate(([0], pos + 1, [len(diagonal)])) - rle = zip([int(n) for n in diagonal[pos[:-1]]], pos[1:] - pos[:-1]) - for level, run_length in rle: - if level != padVal: - P[level - 1, run_length - 1] += 1 + pos, = numpy.where(numpy.diff(diagonal) != 0) + pos = numpy.concatenate(([0], pos + 1, [len(diagonal)])) + rle = zip([int(n) for n in diagonal[pos[:-1]]], pos[1:] - pos[:-1]) + for level, run_length in rle: + if level != padVal: + P[level - 1, run_length - 1] += 1 + if not isMultiElement: + P[:] = 0 # Crop gray-level axis of GLRLMs to between minimum and maximum observed gray-levels # Crop run-length axis of GLRLMs up to maximum observed run-length