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 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..28898c66 100644 --- a/examples/exampleSettings/exampleCT.yaml +++ b/examples/exampleSettings/exampleCT.yaml @@ -14,22 +14,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_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 bfb1db80..f285ffa2 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` @@ -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. @@ -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,9 +382,13 @@ 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. + + .. 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'] @@ -415,7 +419,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. @@ -477,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. @@ -505,13 +509,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 +528,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. @@ -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::