From 956175e1d58cf98eea630578c56d0844339fee5b Mon Sep 17 00:00:00 2001 From: Joost van Griethuysen Date: Mon, 4 Sep 2017 16:09:18 -0400 Subject: [PATCH 1/5] DOCS: Update GLCM formula documentation u_x and u_y are represented in the documentation as being a function of i and j, respectively. However, these variables are both scalars. Update the documentation to reflect this. --- radiomics/glcm.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/radiomics/glcm.py b/radiomics/glcm.py index bfb1db80..858fdc36 100644 --- a/radiomics/glcm.py +++ b/radiomics/glcm.py @@ -50,9 +50,9 @@ class RadiomicsGLCM(base.RadiomicsFeaturesBase): - :math:`p_x(i) = \sum^{N_g}_{j=1}{P(i,j)}` be the marginal row probabilities - :math:`p_y(j) = \sum^{N_g}_{i=1}{P(i,j)}` be the marginal column probabilities - :math:`\mu_x` be the mean gray level intensity of :math:`p_x` and defined as - :math:`\mu_x = \displaystyle\sum^{N_g}_{i=1}\displaystyle\sum^{N_g}_{j=1}{p(i,j)i}` + :math:`\mu_x = \displaystyle\sum^{N_g}_{i=1}{p_x(i)i}` - :math:`\mu_y` be the mean gray level intensity of :math:`p_y` and defined as - :math:`\mu_y = \displaystyle\sum^{N_g}_{i=1}\displaystyle\sum^{N_g}_{j=1}{p(i,j)j}` + :math:`\mu_y = \displaystyle\sum^{N_g}_{j=1}{p_y(j)j}` - :math:`\sigma_x` be the standard deviation of :math:`p_x` - :math:`\sigma_y` be the standard deviation of :math:`p_y` - :math:`p_{x+y}(k) = \sum^{N_g}_{i=1}\sum^{N_g}_{j=1}{p(i,j)},\text{ where }i+j=k,\text{ and }k=2,3,\dots,2N_g` @@ -344,7 +344,7 @@ def getClusterProminenceFeatureValue(self): .. math:: \textit{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)} + {\big( i+j-\mu_x-\mu_y\big)^4p(i,j)} Cluster Prominence is a measure of the skewness and asymmetry of the GLCM. A higher values implies more asymmetry about the mean while a lower value indicates a peak near the mean value and less variation about the mean. @@ -363,7 +363,7 @@ def getClusterShadeFeatureValue(self): .. math:: \textit{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)} + {\big(i+j-\mu_x-\mu_y\big)^3p(i,j)} Cluster Shade is a measure of the skewness and uniformity of the GLCM. A higher cluster shade implies greater asymmetry about the mean. @@ -382,7 +382,7 @@ def getClusterTendencyFeatureValue(self): .. math:: \textit{cluster tendency} = \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)} + {\big(i+j-\mu_x-\mu_y\big)^2p(i,j)} Cluster Tendency is a measure of groupings of voxels with similar gray-level values. """ @@ -415,7 +415,7 @@ def getCorrelationFeatureValue(self): .. math:: - \textit{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)} + \textit{correlation} = \frac{\sum^{N_g}_{i=1}\sum^{N_g}_{j=1}{p(i,j)ij-\mu_x\mu_y}}{\sigma_x(i)\sigma_y(j)} Correlation is a value between 0 (uncorrelated) and 1 (perfectly correlated) showing the linear dependency of gray level values to their respective voxels in the GLCM. From b5bddb5efdd994e3147f023827fe2c79cd98b7a0 Mon Sep 17 00:00:00 2001 From: Joost van Griethuysen Date: Mon, 4 Sep 2017 16:14:12 -0400 Subject: [PATCH 2/5] STYL: Update feature function names to better reflect feature names Some feature function names differed from the feature name due to changes to enhance comparability to IBSI defined features. Update the function names to reflect the feature names. --- radiomics/glcm.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/radiomics/glcm.py b/radiomics/glcm.py index 858fdc36..557206c2 100644 --- a/radiomics/glcm.py +++ b/radiomics/glcm.py @@ -318,13 +318,13 @@ def getAutocorrelationFeatureValue(self): ac = numpy.sum(self.P_glcm * (i * j)[:, :, None], (0, 1)) return ac.mean() - def getAverageIntensityFeatureValue(self): + def getJointAverageFeatureValue(self): r""" **2. Joint Average** .. math:: - \mu_x = \displaystyle\sum^{N_g}_{i=1}\displaystyle\sum^{N_g}_{j=1}{p(i,j)i} + \textit{joint average} = \mu_x = \displaystyle\sum^{N_g}_{i=1}\displaystyle\sum^{N_g}_{j=1}{p(i,j)i} Returns the mean gray level intensity of the :math:`i` distribution. @@ -505,13 +505,13 @@ def getDissimilarityFeatureValue(self): dis = numpy.sum((self.P_glcm * (numpy.abs(i - j))[:, :, None]), (0, 1)) return dis.mean() - def getEnergyFeatureValue(self): + def getJointEnergyFeatureValue(self): r""" **12. Joint Energy** .. math:: - \textit{energy} = \displaystyle\sum^{N_g}_{i=1}\displaystyle\sum^{N_g}_{j=1}{\big(p(i,j)\big)^2} + \textit{joint energy} = \displaystyle\sum^{N_g}_{i=1}\displaystyle\sum^{N_g}_{j=1}{\big(p(i,j)\big)^2} Energy is a measure of homogeneous patterns in the image. A greater Energy implies that there are more instances @@ -524,13 +524,13 @@ def getEnergyFeatureValue(self): ene = numpy.sum((self.P_glcm ** 2), (0, 1)) return ene.mean() - def getEntropyFeatureValue(self): + def getJointEntropyFeatureValue(self): r""" **13. Joint Entropy** .. math:: - \textit{entropy} = -\displaystyle\sum^{N_g}_{i=1}\displaystyle\sum^{N_g}_{j=1} + \textit{joint entropy} = -\displaystyle\sum^{N_g}_{i=1}\displaystyle\sum^{N_g}_{j=1} {p(i,j)\log_2\big(p(i,j)+\epsilon\big)} Entropy is a measure of the randomness/variability in neighborhood intensity values. From de633a95a6a20b9060e0586afdeb4fe7e5dd5cb1 Mon Sep 17 00:00:00 2001 From: Joost van Griethuysen Date: Mon, 4 Sep 2017 16:37:44 -0400 Subject: [PATCH 3/5] Remove Sum Variance feature Sum Variance is mathematically equal to Cluster Tendency, therefore remove Sum Variance from PyRadiomics. Add a new section to the documentation that lists removed features with the reason why this was done (here including the proof that Sum Variance and Cluster Tendency are equal). Additionally, Sum Average is very similar to Joint Average (if and only if the GLCM is symmetrical, Sum Average = 2 * Joint Average). As there is a difference possible between these features, but not in the case of 'default' settings, Sum Average is not removed, but disabled in the default parameter files. --- docs/features.rst | 2 +- docs/index.rst | 1 + docs/removedfeatures.rst | 88 +++++++++++++++++++ examples/exampleSettings/Params.yaml | 33 ++++++- examples/exampleSettings/exampleCT.yaml | 16 +++- examples/exampleSettings/exampleMR_3mm.yaml | 56 ++++++++---- examples/exampleSettings/exampleMR_5mm.yaml | 56 ++++++++---- .../exampleMR_NoResampling.yaml | 56 ++++++++---- radiomics/glcm.py | 29 +++--- 9 files changed, 268 insertions(+), 69 deletions(-) create mode 100644 docs/removedfeatures.rst diff --git a/docs/features.rst b/docs/features.rst index e77bce11..44b82cc1 100644 --- a/docs/features.rst +++ b/docs/features.rst @@ -9,7 +9,7 @@ subdivided into the following classes: * :ref:`radiomics-firstorder-label` (19 features) * :ref:`radiomics-shape-label` (16 features) -* :ref:`radiomics-glcm-label` (27 features) +* :ref:`radiomics-glcm-label` (26 features) * :ref:`radiomics-glszm-label` (16 features) * :ref:`radiomics-glrlm-label` (16 features) diff --git a/docs/index.rst b/docs/index.rst index 271cbe5f..8922fc92 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -41,6 +41,7 @@ Table of Contents customization radiomics features + removedfeatures contributing developers FAQs diff --git a/docs/removedfeatures.rst b/docs/removedfeatures.rst new file mode 100644 index 00000000..25e8c294 --- /dev/null +++ b/docs/removedfeatures.rst @@ -0,0 +1,88 @@ +.. _radiomics-removed-features-label: + +========================== +Excluded Radiomic Features +========================== + +Some commonly know features are not supported (anymore) in PyRadiomics. These features are listed here, so as to provide +a complete overview, as well as argumentation for why these features are excluded from PyRadiomics + +Excluded GLCM Features +---------------------- + +For included features and class definition, see :ref:`radiomics-glcm-label`. + +.. _radiomics-excluded-sumvariance-label: + +1. Sum Variance +############### + +.. math:: + \textit{sum variance} = \displaystyle\sum^{2N_g}_{k=2}{(k-SA)^2p_{x+y}(k)} + +Sum Variance is a measure of heterogeneity that places higher weights on +neighboring intensity level pairs that deviate more from the mean. + +This feature has been removed, as it is mathematically identical to Cluster Tendency (see +:py:func:`~radiomics.glcm.RadiomicsGLCM.getClusterTendencyFeatureValue()`). + +The mathematical proof is as follows: + +(1) As defined in GLCM, + :math:`p_{x+y}(k) = \sum^{N_g}_{i=1}\sum^{N_g}_{j=1}{p(i,j)},\text{ where }i+j=k, k \in \{2, 3, \dots, 2N_g\}` + +(2) Starting with cluster tendency as defined in GLCM: + +.. math:: + \textit{cluster tendency} = \displaystyle\sum^{N_g}_{i=1}\displaystyle\sum^{N_g}_{j=1} + {\big(i+j-\mu_x-\mu_y\big)^2p(i,j)} + + = \displaystyle\sum^{2N_g}_{k=2}{\Big[\displaystyle\sum^{N_g}_{i=1}\displaystyle\sum^{N_g}_{j=1} + {\big(i+j-\mu_x-\mu_y\big)^2p(i,j)} \text{, where }i+j=k\Big]} + + = \displaystyle\sum^{2N_g}_{k=2}{\Big[\displaystyle\sum^{N_g}_{i=1}\displaystyle\sum^{N_g}_{j=1} + {\big(k-(\mu_x+\mu_y)\big)^2p(i,j)} \text{, where }i+j=k \Big]} + +.. note:: + Because inside the sum :math:`\sum^{2N_g}_{k=2}`, :math:`k` is a constant, and so are :math:`\mu_x` and + :math:`\mu_y`, :math:`\big(k-(\mu_x+\mu_y)\big)^2` is constant and can be taken outside the inner sum + :math:`\sum^{N_g}_{i=1}\sum^{N_g}_{j=1}`. + +.. math:: + = \displaystyle\sum^{2N_g}_{k=2}{\Big[\big(k-(\mu_x+\mu_y)\big)^2\displaystyle\sum^{N_g}_{i=1} + \displaystyle\sum^{N_g}_{j=1}{p(i,j)} \text{, where }i+j=k \Big]} + +(3) Using (1.) and (2.) + +.. math:: + \textit{cluster tendency} = \displaystyle\sum^{2N_g}_{k=2}{\Big[\big(k-(\mu_x+\mu_y)\big)^2p_{x+y}(k)\Big]} + +(4) As defined in GLCM, :math:`p_x(i) = \sum^{N_g}_{j=1}{P(i,j)}` and :math:`\mu_x = \sum^{N_g}_{i=1}{p_x(i)i}`, + therefore :math:`\mu_x = \sum^{N_g}_{i=1}\sum^{N_g}_{j=1}{P(i,j)i}` + +(5) Similarly as in (4.), :math:`\mu_y = \sum^{N_g}_{j=1}\sum^{N_g}_{i=1}{P(i,j)j}` + +(6) Using (4.) and (5.), :math:`\mu_x` and :math:`\mu_y` can then be combined as follows: + +.. math:: + \mu_x + \mu_y = \displaystyle\sum^{N_g}_{i=1}\displaystyle\sum^{N_g}_{j=1}{P(i,j)i} + + \displaystyle\sum^{N_g}_{j=1}\displaystyle\sum^{N_g}_{i=1}{P(i,j)j} + + = \displaystyle\sum^{N_g}_{j=1}\displaystyle\sum^{N_g}_{i=1}{P(i,j)i + P(i, j)j} + + = \displaystyle\sum^{N_g}_{j=1}\displaystyle\sum^{N_g}_{i=1}{P(i,j)(i + j)} + + = \displaystyle\sum^{2N_g}_{k=2}{\Big[\displaystyle\sum^{N_g}_{j=1} + \displaystyle\sum^{N_g}_{i=1}{P(i,j)(i + j)} \text{, where } k = i + j\Big]} + + = \displaystyle\sum^{2N_g}_{k=2}{p_{x+y}(k)k} = \textit{sum average (SA)} + +(7) Combining (3.) and (6.) yields the following formula: + +.. math:: + + \text{Cluster Tendency} = + \displaystyle\sum^{2N_g}_{k=2}{\Big[\big(k-SA\big)^2p_{x+y}(k)\Big]} = + \textit{ sum variance} + +Q.E.D diff --git a/examples/exampleSettings/Params.yaml b/examples/exampleSettings/Params.yaml index b63a6d47..645f39f5 100644 --- a/examples/exampleSettings/Params.yaml +++ b/examples/exampleSettings/Params.yaml @@ -31,7 +31,7 @@ imageType: # Featureclasses, from which features must be calculated. If a featureclass is not mentioned, no features are calculated # for that class. Otherwise, the specified features are calculated, or, if none are specified, all are calculated. featureClass: - shape: + shape: # disable redundant Compactness 1 and Compactness 2 features by specifying all other shape features - 'Volume' - 'SurfaceArea' - 'SurfaceVolumeRatio' @@ -45,8 +45,33 @@ featureClass: - 'MinorAxis' - 'LeastAxis' - 'Elongation' - - 'Flatness' # Only enable these shape descriptors (disables redundant Compactness 1 and Compactness 2) + - 'Flatness' firstorder: [] # specifying an empty list has the same effect as specifying nothing. - glcm: # for lists none values are allowed, in this case, all features are enabled - glrlm: + glcm: # Disable SumAverage by specifying all other GLCM features available + - 'Autocorrelation' + - 'JointAverage' + - 'ClusterProminence' + - 'ClusterShade' + - 'ClusterTendency' + - 'Contrast' + - 'Correlation' + - 'DifferenceAverage' + - 'DifferenceEntropy' + - 'DifferenceVariance' + - 'Dissimilarity' + - 'JointEnergy' + - 'JointEntropy' + - 'Homogeneity1' + - 'Homogeneity2' + - 'Imc1' + - 'Imc2' + - 'Idm' + - 'Idmn' + - 'Id' + - 'Idn' + - 'InverseVariance' + - 'MaximumProbability' + - 'SumEntropy' + - 'SumSquares' + glrlm: # for lists none values are allowed, in this case, all features are enabled glszm: diff --git a/examples/exampleSettings/exampleCT.yaml b/examples/exampleSettings/exampleCT.yaml index d5366baa..58ad7cd1 100644 --- a/examples/exampleSettings/exampleCT.yaml +++ b/examples/exampleSettings/exampleCT.yaml @@ -29,7 +29,21 @@ featureClass: 'Elongation', 'Flatness'] # Only enable these shape descriptors (disables redundant Compactness 1 and Compactness 2) firstorder: - glcm: + glcm: # disable redundant Compactness 1 and Compactness 2 features by specifying all other shape features + - 'Volume' + - 'SurfaceArea' + - 'SurfaceVolumeRatio' + - 'Sphericity' + - 'SphericalDisproportion' + - 'Maximum3DDiameter' + - 'Maximum2DDiameterSlice' + - 'Maximum2DDiameterColumn' + - 'Maximum2DDiameterRow' + - 'MajorAxis' + - 'MinorAxis' + - 'LeastAxis' + - 'Elongation' + - 'Flatness' glrlm: glszm: diff --git a/examples/exampleSettings/exampleMR_3mm.yaml b/examples/exampleSettings/exampleMR_3mm.yaml index 4d71f983..9b991029 100644 --- a/examples/exampleSettings/exampleMR_3mm.yaml +++ b/examples/exampleSettings/exampleMR_3mm.yaml @@ -16,22 +16,48 @@ imageType: Wavelet: {} featureClass: - shape: ['Volume', - 'SurfaceArea', - 'SurfaceVolumeRatio', - 'Sphericity', - 'SphericalDisproportion', - 'Maximum3DDiameter', - 'Maximum2DDiameterSlice', - 'Maximum2DDiameterColumn', - 'Maximum2DDiameterRow', - 'MajorAxis', - 'MinorAxis', - 'LeastAxis', - 'Elongation', - 'Flatness'] # Only enable these shape descriptors (disables redundant Compactness 1 and Compactness 2) + shape: # disable redundant Compactness 1 and Compactness 2 features by specifying all other shape features + - 'Volume' + - 'SurfaceArea' + - 'SurfaceVolumeRatio' + - 'Sphericity' + - 'SphericalDisproportion' + - 'Maximum3DDiameter' + - 'Maximum2DDiameterSlice' + - 'Maximum2DDiameterColumn' + - 'Maximum2DDiameterRow' + - 'MajorAxis' + - 'MinorAxis' + - 'LeastAxis' + - 'Elongation' + - 'Flatness' firstorder: - glcm: + glcm: # Disable SumAverage by specifying all other GLCM features available + - 'Autocorrelation' + - 'JointAverage' + - 'ClusterProminence' + - 'ClusterShade' + - 'ClusterTendency' + - 'Contrast' + - 'Correlation' + - 'DifferenceAverage' + - 'DifferenceEntropy' + - 'DifferenceVariance' + - 'Dissimilarity' + - 'JointEnergy' + - 'JointEntropy' + - 'Homogeneity1' + - 'Homogeneity2' + - 'Imc1' + - 'Imc2' + - 'Idm' + - 'Idmn' + - 'Id' + - 'Idn' + - 'InverseVariance' + - 'MaximumProbability' + - 'SumEntropy' + - 'SumSquares' glrlm: glszm: diff --git a/examples/exampleSettings/exampleMR_5mm.yaml b/examples/exampleSettings/exampleMR_5mm.yaml index 329b131e..fc6c3bbc 100644 --- a/examples/exampleSettings/exampleMR_5mm.yaml +++ b/examples/exampleSettings/exampleMR_5mm.yaml @@ -15,22 +15,48 @@ imageType: Wavelet: {} featureClass: - shape: ['Volume', - 'SurfaceArea', - 'SurfaceVolumeRatio', - 'Sphericity', - 'SphericalDisproportion', - 'Maximum3DDiameter', - 'Maximum2DDiameterSlice', - 'Maximum2DDiameterColumn', - 'Maximum2DDiameterRow', - 'MajorAxis', - 'MinorAxis', - 'LeastAxis', - 'Elongation', - 'Flatness'] # Only enable these shape descriptors (disables redundant Compactness 1 and Compactness 2) + shape: # disable redundant Compactness 1 and Compactness 2 features by specifying all other shape features + - 'Volume' + - 'SurfaceArea' + - 'SurfaceVolumeRatio' + - 'Sphericity' + - 'SphericalDisproportion' + - 'Maximum3DDiameter' + - 'Maximum2DDiameterSlice' + - 'Maximum2DDiameterColumn' + - 'Maximum2DDiameterRow' + - 'MajorAxis' + - 'MinorAxis' + - 'LeastAxis' + - 'Elongation' + - 'Flatness' firstorder: - glcm: + glcm: # Disable SumAverage by specifying all other GLCM features available + - 'Autocorrelation' + - 'JointAverage' + - 'ClusterProminence' + - 'ClusterShade' + - 'ClusterTendency' + - 'Contrast' + - 'Correlation' + - 'DifferenceAverage' + - 'DifferenceEntropy' + - 'DifferenceVariance' + - 'Dissimilarity' + - 'JointEnergy' + - 'JointEntropy' + - 'Homogeneity1' + - 'Homogeneity2' + - 'Imc1' + - 'Imc2' + - 'Idm' + - 'Idmn' + - 'Id' + - 'Idn' + - 'InverseVariance' + - 'MaximumProbability' + - 'SumEntropy' + - 'SumSquares' glrlm: glszm: diff --git a/examples/exampleSettings/exampleMR_NoResampling.yaml b/examples/exampleSettings/exampleMR_NoResampling.yaml index 7360b71e..e43f25a1 100644 --- a/examples/exampleSettings/exampleMR_NoResampling.yaml +++ b/examples/exampleSettings/exampleMR_NoResampling.yaml @@ -19,22 +19,48 @@ imageType: Wavelet: {} featureClass: - shape: ['Volume', - 'SurfaceArea', - 'SurfaceVolumeRatio', - 'Sphericity', - 'SphericalDisproportion', - 'Maximum3DDiameter', - 'Maximum2DDiameterSlice', - 'Maximum2DDiameterColumn', - 'Maximum2DDiameterRow', - 'MajorAxis', - 'MinorAxis', - 'LeastAxis', - 'Elongation', - 'Flatness'] # Only enable these shape descriptors (disables redundant Compactness 1 and Compactness 2) + shape: # disable redundant Compactness 1 and Compactness 2 features by specifying all other shape features + - 'Volume' + - 'SurfaceArea' + - 'SurfaceVolumeRatio' + - 'Sphericity' + - 'SphericalDisproportion' + - 'Maximum3DDiameter' + - 'Maximum2DDiameterSlice' + - 'Maximum2DDiameterColumn' + - 'Maximum2DDiameterRow' + - 'MajorAxis' + - 'MinorAxis' + - 'LeastAxis' + - 'Elongation' + - 'Flatness' firstorder: - glcm: + glcm: # Disable SumAverage by specifying all other GLCM features available + - 'Autocorrelation' + - 'JointAverage' + - 'ClusterProminence' + - 'ClusterShade' + - 'ClusterTendency' + - 'Contrast' + - 'Correlation' + - 'DifferenceAverage' + - 'DifferenceEntropy' + - 'DifferenceVariance' + - 'Dissimilarity' + - 'JointEnergy' + - 'JointEntropy' + - 'Homogeneity1' + - 'Homogeneity2' + - 'Imc1' + - 'Imc2' + - 'Idm' + - 'Idmn' + - 'Id' + - 'Idn' + - 'InverseVariance' + - 'MaximumProbability' + - 'SumEntropy' + - 'SumSquares' glrlm: glszm: diff --git a/radiomics/glcm.py b/radiomics/glcm.py index 557206c2..ec59bc36 100644 --- a/radiomics/glcm.py +++ b/radiomics/glcm.py @@ -385,6 +385,10 @@ def getClusterTendencyFeatureValue(self): {\big(i+j-\mu_x-\mu_y\big)^2p(i,j)} Cluster Tendency is a measure of groupings of voxels with similar gray-level values. + + .. note:: + Cluster Tendency is mathematically identical to Sum Variance, the latter has therefore been removed from + PyRadiomics. See :ref:`here ` for the proof. """ i = self.coefficients['i'] j = self.coefficients['j'] @@ -745,6 +749,12 @@ def getSumAverageFeatureValue(self): Sum Average measures the relationship between occurrences of pairs with lower intensity values and occurrences of pairs with higher intensity values. + + .. warning:: + When GLCM is symmetrical, :math:`\mu_x = \mu_y`, and therefore :math:`\text{Sum Average} = \mu_x + \mu_y = + 2 \mu_x = 2 * Joint Average`. See formulas (4.), (5.) and (6.) defined + :ref:`here ` for the proof that :math:`\text{Sum Average} = \mu_x + \mu_y`. + In the default parameter files provided in the ``examples/exampleSettings``, this feature has been disabled. """ pxAddy = self.coefficients['pxAddy'] kValuesSum = self.coefficients['kValuesSum'] @@ -766,26 +776,9 @@ def getSumEntropyFeatureValue(self): sumentr = (-1) * numpy.sum((pxAddy * numpy.log2(pxAddy + eps)), 0) return sumentr.mean() - def getSumVarianceFeatureValue(self): - r""" - **26. Sum Variance** - - .. math:: - - \textit{sum variance} = \displaystyle\sum^{2N_g}_{k=2}{(k-SA)^2p_{x+y}(k)} - - Sum Variance is a measure of heterogeneity that places higher weights on - neighboring intensity level pairs that deviate more from the mean. - """ - pxAddy = self.coefficients['pxAddy'] - kValuesSum = self.coefficients['kValuesSum'] - sumavg = numpy.sum((kValuesSum[:, None] * pxAddy), 0, keepdims=True) - sumvar = numpy.sum((pxAddy * ((kValuesSum[:, None] - sumavg) ** 2)), 0) - return sumvar.mean() - def getSumSquaresFeatureValue(self): r""" - **27. Sum of Squares** + **26. Sum of Squares** .. math:: From 81f32fd73d7b4152206390898838db660f6b1901 Mon Sep 17 00:00:00 2001 From: Joost van Griethuysen Date: Mon, 4 Sep 2017 16:52:20 -0400 Subject: [PATCH 4/5] Update baseline --- data/baseline/baseline_glcm.csv | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/data/baseline/baseline_glcm.csv b/data/baseline/baseline_glcm.csv index 1f33d1d6..8737ebc2 100644 --- a/data/baseline/baseline_glcm.csv +++ b/data/baseline/baseline_glcm.csv @@ -1,6 +1,6 @@ -Patient ID,general_info_BoundingBox,general_info_GeneralSettings,general_info_ImageHash,general_info_ImageSpacing,general_info_InputImages,general_info_MaskHash,general_info_Version,general_info_VolumeNum,general_info_VoxelNum,Homogeneity1,Homogeneity2,ClusterShade,MaximumProbability,Idmn,SumVariance,Contrast,DifferenceEntropy,InverseVariance,Entropy,Dissimilarity,DifferenceVariance,Idn,Idm,Correlation,Autocorrelation,SumEntropy,AverageIntensity,Energy,SumSquares,ClusterProminence,SumAverage,Imc2,Imc1,DifferenceAverage,Id,ClusterTendency -brain1,"(162, 84, 11, 47, 70, 7)","{'verbose': False, 'voxelArrayShift': 2000, 'binWidth': 25, 'label': 1, 'interpolator': None, 'symmetricalGLCM': False, 'resampledPixelSpacing': None, 'gldm_a': 0, 'weightingNorm': None, 'padDistance': 5}",5c9ce3ca174f0f8324aa4d277e0fef82dc5ac566,"(0.7812499999999999, 0.7812499999999999, 6.499999999999998)",{'original': {}},9dc2c3137b31fd872997d92c9a92d5178126d9d3,0.post403.dev0+gd611f07,2,4137,0.28722572382985151,0.20022255640475706,19.605083427287216,0.008193101942105081,0.961402169623227,108.73139325453903,47.492125114429797,3.7440609780664209,0.19881884197093194,8.6484091908787004,5.2844687898663176,16.655637050270975,0.87260521573971694,0.20022255640475706,0.39219743588570566,289.54369940172597,5.354241321485615,16.60808368859043,0.003151601429689756,40.55236483913805,27995.937591943148,33.107615448855022,0.79188798671101246,-0.12298081261731311,5.2844687898663176,0.28722572382985151,108.73139325453907 -brain2,"(205, 155, 8, 20, 15, 3)","{'verbose': False, 'voxelArrayShift': 2000, 'binWidth': 25, 'label': 1, 'interpolator': None, 'symmetricalGLCM': False, 'resampledPixelSpacing': None, 'gldm_a': 0, 'weightingNorm': None, 'padDistance': 5}",f2b8fbc4d5d1da08a1a70e79a301f8a830139438,"(0.7812499999999999, 0.7812499999999999, 6.499999999999998)",{'original': {}},b41049c71633e194bee4891750392b72eabd8800,0.post403.dev0+gd611f07,1,453,0.34588791642687811,0.26177848833510498,127.13809223840238,0.0597732663763283,0.97092709086072326,42.317452064295658,29.293839050702996,3.3390497846557254,0.25338046923906615,6.2202489517449395,3.9826729595606403,11.757829127963504,0.89204192659477488,0.26177848833510498,0.31298362781586209,276.9390375378519,4.3841213671951538,17.596367643690353,0.021296604313774989,16.074173100898356,7743.448102798925,33.084919329182931,0.94806637990321463,-0.30140675421432073,3.9826729595606398,0.34588791642687811,42.317452064295665 -breast1,"(21, 64, 8, 9, 12, 3)","{'verbose': False, 'voxelArrayShift': 2000, 'binWidth': 25, 'label': 1, 'interpolator': None, 'symmetricalGLCM': False, 'resampledPixelSpacing': None, 'gldm_a': 0, 'weightingNorm': None, 'padDistance': 5}",016951a8f9e8e5de21092d9d62b77262f92e04a5,"(0.664062, 0.664062, 2.1)",{'original': {}},5aa7d57fd57e83125b605c036c40f4a0d0cfd3e4,0.post403.dev0+gd611f07,1,143,0.73109230839874451,0.72442214443357622,-0.016711211805404854,0.29665628002001326,0.93749593957145183,1.1696127286855562,0.67121866250587736,1.1846976792586774,0.48362030098551811,2.713185137166831,0.5711662030283523,0.32725642574315206,0.86221107221678805,0.72442214443357622,0.28882475722469503,3.9663379593499664,2.0621987981343954,2.0314251665935505,0.18015057742115115,0.45588441376750161,3.2994515259044608,3.9170802211991651,0.46586325566090836,-0.10371357440316083,0.5711662030283523,0.73109230839874451,1.1696127286855562 -lung1,"(206, 347, 32, 24, 26, 3)","{'verbose': False, 'voxelArrayShift': 2000, 'binWidth': 25, 'label': 1, 'interpolator': None, 'symmetricalGLCM': False, 'resampledPixelSpacing': None, 'gldm_a': 0, 'weightingNorm': None, 'padDistance': 5}",34dca4200809a5e76c702d6b9503d958093057a3,"(0.5703125, 0.5703125, 5.0)",{'original': {}},054d887740012177bd1f9031ddac2b67170af0f3,0.post403.dev0+gd611f07,1,837,0.41736196376573204,0.34435017672215545,-345.71336725148899,0.08912560596848712,0.97258239381784684,58.74756668430426,20.713449304070664,3.1875245017550018,0.27869716669593048,6.6556227958601175,3.2166030915302346,9.38199581278284,0.89963070737626616,0.34435017672215545,0.4968957940703928,411.4164748228452,4.6355019464777119,19.570210424032926,0.019550376521576325,21.652368580855146,9732.6943959902492,40.09024968089912,0.89429023840987421,-0.22722644766515582,3.2166030915302346,0.41736196376573204,58.747566684304267 -lung2,"(318, 333, 15, 87, 66, 11)","{'verbose': False, 'voxelArrayShift': 2000, 'binWidth': 25, 'label': 1, 'interpolator': None, 'symmetricalGLCM': False, 'resampledPixelSpacing': None, 'gldm_a': 0, 'weightingNorm': None, 'padDistance': 5}",14f57fd04838eb8c9cca2a0dd871d29971585975,"(0.6269531, 0.6269531, 5.0)",{'original': {}},e284ff05593bc6cb2747261882e452d4efbccb3a,0.post403.dev0+gd611f07,1,24644,0.67488828052808181,0.65209771741148159,-498.73190629686474,0.32422085412558954,0.99472500276765008,28.339974380216191,12.115468558259831,2.1805601671536725,0.35136435757987061,4.3065420577384446,1.5501077045805824,9.4711179692288354,0.97084505602500215,0.65209771741148159,0.36291098448004738,1250.7846278881173,3.1809315369280782,35.275329629029159,0.15022980791791918,10.631815040073569,13254.853382802215,70.617306920893128,0.57027092518828848,-0.13541543952656429,1.5501077045805824,0.67488828052808181,28.339974380216198 +Patient ID,general_info_BoundingBox,general_info_GeneralSettings,general_info_ImageHash,general_info_ImageSpacing,general_info_InputImages,general_info_MaskHash,general_info_Version,general_info_VolumeNum,general_info_VoxelNum,Homogeneity1,Homogeneity2,ClusterShade,MaximumProbability,Idmn,Contrast,DifferenceEntropy,InverseVariance,JointEntropy,Dissimilarity,DifferenceVariance,Idn,Idm,Correlation,Autocorrelation,SumEntropy,JointAverage,JointEnergy,SumSquares,ClusterProminence,SumAverage,Imc2,Imc1,DifferenceAverage,Id,ClusterTendency +brain1,"(162, 84, 11, 47, 70, 7)","{'verbose': False, 'voxelArrayShift': 2000, 'binWidth': 25, 'label': 1, 'interpolator': None, 'symmetricalGLCM': False, 'resampledPixelSpacing': None, 'gldm_a': 0, 'weightingNorm': None, 'padDistance': 5}",5c9ce3ca174f0f8324aa4d277e0fef82dc5ac566,"(0.7812499999999999, 0.7812499999999999, 6.499999999999998)",{'original': {}},9dc2c3137b31fd872997d92c9a92d5178126d9d3,0.post403.dev0+gd611f07,2,4137,0.287225724,0.200222556,19.60508343,0.008193102,0.96140217,47.49212511,3.744060978,0.198818842,8.648409191,5.28446879,16.65563705,0.872605216,0.200222556,0.392197436,289.5436994,5.354241321,16.60808369,0.003151601,40.55236484,27995.93759,33.10761545,0.791887987,-0.122980813,5.28446879,0.287225724,108.7313933 +brain2,"(205, 155, 8, 20, 15, 3)","{'verbose': False, 'voxelArrayShift': 2000, 'binWidth': 25, 'label': 1, 'interpolator': None, 'symmetricalGLCM': False, 'resampledPixelSpacing': None, 'gldm_a': 0, 'weightingNorm': None, 'padDistance': 5}",f2b8fbc4d5d1da08a1a70e79a301f8a830139438,"(0.7812499999999999, 0.7812499999999999, 6.499999999999998)",{'original': {}},b41049c71633e194bee4891750392b72eabd8800,0.post403.dev0+gd611f07,1,453,0.345887916,0.261778488,127.1380922,0.059773266,0.970927091,29.29383905,3.339049785,0.253380469,6.220248952,3.98267296,11.75782913,0.892041927,0.261778488,0.312983628,276.9390375,4.384121367,17.59636764,0.021296604,16.0741731,7743.448103,33.08491933,0.94806638,-0.301406754,3.98267296,0.345887916,42.31745206 +breast1,"(21, 64, 8, 9, 12, 3)","{'verbose': False, 'voxelArrayShift': 2000, 'binWidth': 25, 'label': 1, 'interpolator': None, 'symmetricalGLCM': False, 'resampledPixelSpacing': None, 'gldm_a': 0, 'weightingNorm': None, 'padDistance': 5}",016951a8f9e8e5de21092d9d62b77262f92e04a5,"(0.664062, 0.664062, 2.1)",{'original': {}},5aa7d57fd57e83125b605c036c40f4a0d0cfd3e4,0.post403.dev0+gd611f07,1,143,0.731092308,0.724422144,-0.016711212,0.29665628,0.93749594,0.671218663,1.184697679,0.483620301,2.713185137,0.571166203,0.327256426,0.862211072,0.724422144,0.288824757,3.966337959,2.062198798,2.031425167,0.180150577,0.455884414,3.299451526,3.917080221,0.465863256,-0.103713574,0.571166203,0.731092308,1.169612729 +lung1,"(206, 347, 32, 24, 26, 3)","{'verbose': False, 'voxelArrayShift': 2000, 'binWidth': 25, 'label': 1, 'interpolator': None, 'symmetricalGLCM': False, 'resampledPixelSpacing': None, 'gldm_a': 0, 'weightingNorm': None, 'padDistance': 5}",34dca4200809a5e76c702d6b9503d958093057a3,"(0.5703125, 0.5703125, 5.0)",{'original': {}},054d887740012177bd1f9031ddac2b67170af0f3,0.post403.dev0+gd611f07,1,837,0.417361964,0.344350177,-345.7133673,0.089125606,0.972582394,20.7134493,3.187524502,0.278697167,6.655622796,3.216603092,9.381995813,0.899630707,0.344350177,0.496895794,411.4164748,4.635501946,19.57021042,0.019550377,21.65236858,9732.694396,40.09024968,0.894290238,-0.227226448,3.216603092,0.417361964,58.74756668 +lung2,"(318, 333, 15, 87, 66, 11)","{'verbose': False, 'voxelArrayShift': 2000, 'binWidth': 25, 'label': 1, 'interpolator': None, 'symmetricalGLCM': False, 'resampledPixelSpacing': None, 'gldm_a': 0, 'weightingNorm': None, 'padDistance': 5}",14f57fd04838eb8c9cca2a0dd871d29971585975,"(0.6269531, 0.6269531, 5.0)",{'original': {}},e284ff05593bc6cb2747261882e452d4efbccb3a,0.post403.dev0+gd611f07,1,24644,0.674888281,0.652097717,-498.7319063,0.324220854,0.994725003,12.11546856,2.180560167,0.351364358,4.306542058,1.550107705,9.471117969,0.970845056,0.652097717,0.362910984,1250.784628,3.180931537,35.27532963,0.150229808,10.63181504,13254.85338,70.61730692,0.570270925,-0.13541544,1.550107705,0.674888281,28.33997438 From 147c1c8d4b014f85251d7d7985de9e575af4533b Mon Sep 17 00:00:00 2001 From: Joost van Griethuysen Date: Mon, 4 Sep 2017 20:15:31 -0400 Subject: [PATCH 5/5] STYL: Correct difference variance formula (docs) Correct error in difference variance formula as pointed out by @clarehchao. Additionally, fix an error in the exampleCT settings (enabled shape features erroneously listed as glcm features). --- examples/exampleSettings/exampleCT.yaml | 44 ++++++++++++++++--------- radiomics/glcm.py | 2 +- 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/examples/exampleSettings/exampleCT.yaml b/examples/exampleSettings/exampleCT.yaml index 58ad7cd1..28898c66 100644 --- a/examples/exampleSettings/exampleCT.yaml +++ b/examples/exampleSettings/exampleCT.yaml @@ -14,22 +14,7 @@ imageType: Wavelet: {} featureClass: - shape: ['Volume', - 'SurfaceArea', - 'SurfaceVolumeRatio', - 'Sphericity', - 'SphericalDisproportion', - 'Maximum3DDiameter', - 'Maximum2DDiameterSlice', - 'Maximum2DDiameterColumn', - 'Maximum2DDiameterRow', - 'MajorAxis', - 'MinorAxis', - 'LeastAxis', - 'Elongation', - 'Flatness'] # Only enable these shape descriptors (disables redundant Compactness 1 and Compactness 2) - firstorder: - glcm: # disable redundant Compactness 1 and Compactness 2 features by specifying all other shape features + shape: # disable redundant Compactness 1 and Compactness 2 features by specifying all other shape features - 'Volume' - 'SurfaceArea' - 'SurfaceVolumeRatio' @@ -44,6 +29,33 @@ featureClass: - 'LeastAxis' - 'Elongation' - 'Flatness' + firstorder: + glcm: # Disable SumAverage by specifying all other GLCM features available + - 'Autocorrelation' + - 'JointAverage' + - 'ClusterProminence' + - 'ClusterShade' + - 'ClusterTendency' + - 'Contrast' + - 'Correlation' + - 'DifferenceAverage' + - 'DifferenceEntropy' + - 'DifferenceVariance' + - 'Dissimilarity' + - 'JointEnergy' + - 'JointEntropy' + - 'Homogeneity1' + - 'Homogeneity2' + - 'Imc1' + - 'Imc2' + - 'Idm' + - 'Idmn' + - 'Id' + - 'Idn' + - 'InverseVariance' + - 'MaximumProbability' + - 'SumEntropy' + - 'SumSquares' glrlm: glszm: diff --git a/radiomics/glcm.py b/radiomics/glcm.py index ec59bc36..f285ffa2 100644 --- a/radiomics/glcm.py +++ b/radiomics/glcm.py @@ -481,7 +481,7 @@ def getDifferenceVarianceFeatureValue(self): .. math:: - \textit{difference variance} = \displaystyle\sum^{N_g-1}_{k=0}{(1-DA)^2p_{x-y}(k)} + \textit{difference variance} = \displaystyle\sum^{N_g-1}_{k=0}{(k-DA)^2p_{x-y}(k)} Difference Variance is a measure of heterogeneity that places higher weights on differing intensity level pairs that deviate more from the mean.