Skip to content

Commit

Permalink
ENH: Reconfigure tests
Browse files Browse the repository at this point in the history
Allows for multiple configurations using the same test cases (e.g. force2D extraction, weighting).
Also redefines the structure of the baseline files, as this allows for better tracking of changes.
  • Loading branch information
JoostJM committed Mar 8, 2018
1 parent ca94c9e commit 617ddcc
Show file tree
Hide file tree
Showing 11 changed files with 405 additions and 192 deletions.
57 changes: 16 additions & 41 deletions bin/addClassToBaseline.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,41 +5,26 @@
import csv
import os

import six
from radiomics import featureextractor, getTestCase, imageoperations

from radiomics import featureextractor, imageoperations
TEST_CASES = ('brain1', 'brain2', 'breast1', 'lung1', 'lung2')


def main():
global TEST_CASES
dataDir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "data")
baselineDir = os.path.join(dataDir, "baseline")

testCases = []

kwargs = {'binWidth': 25,
'interpolator': None,
'resampledPixelSpacing': None,
'padDistance': 5,
'voxelArrayShift': 2000,
'symmetricalGLCM': False,
'weightingNorm': None,
'gldm_a': 0}

extractor = featureextractor.RadiomicsFeaturesExtractor(**kwargs)

for cls in extractor.getFeatureClassNames():
if os.path.exists(os.path.join(baselineDir, 'baseline_%s.csv' % (cls))):
with open(os.path.join(baselineDir, 'baseline_%s.csv' % (cls)), 'rb') as baselineFile:
csvReader = csv.reader(baselineFile)
six.next(csvReader) # Skip header row
for testRow in csvReader:
testCases += [testRow[0]]
if len(testCases) > 0: break

if len(testCases) == 0:
print("No baselinefiles containing testcases found, exiting...")
exit(-1)

newClasses = [cls for cls in extractor.getFeatureClassNames() if
not os.path.exists(os.path.join(baselineDir, 'baseline_%s.csv' % (cls)))]

Expand All @@ -51,9 +36,6 @@ def main():

newBaseline = {}

# When C matrices is merged, force baseline to be build using the Python implementation of the functions.
# radiomics.pythonMatrixCalculation(True)

extractor.disableAllFeatures()
extractor.disableAllImageTypes()

Expand All @@ -63,42 +45,35 @@ def main():
newBaseline[cls] = {}

print("Computing new baseline")
for testCase in testCases:
for testCase in TEST_CASES:
print("\tCalculating test case", testCase)
imagePath = os.path.join(dataDir, testCase + '_image.nrrd')
maskPath = os.path.join(dataDir, testCase + '_label.nrrd')
imagePath, maskPath = getTestCase(testCase)
image, mask = extractor.loadImage(imagePath, maskPath)
if image is None or mask is None:
print("Error during loading of image/mask, testcase:", testCase)
continue # testImage or mask not found / error during loading

provenance = extractor.getProvenance(imagePath, maskPath, mask)

bb, correctedMask = imageoperations.checkMask(image, mask)
if correctedMask is not None:
mask = correctedMask
image, mask = imageoperations.cropToTumorMask(image, mask, bb)
for cls in newClasses:
print("\t\tCalculating class", cls)
extractor.disableAllFeatures()
extractor.enableFeatureClassByName(cls)
newBaseline[cls][testCase] = collections.OrderedDict()
newBaseline[cls][testCase]["Patient ID"] = testCase
newBaseline[cls][testCase].update(provenance)
featureClass = extractor.featureClasses[cls](image, mask, **extractor.settings)
featureClass.enableAllFeatures()
featureClass.calculateFeatures()
newBaseline[cls][testCase].update(featureClass.featureValues)
newBaseline[cls][testCase]['general_info_TestCase'] = testCase
newBaseline[cls][testCase].update(extractor.execute(image, mask))

print("Writing new baseline")
for cls in newClasses:
baselineFile = os.path.join(baselineDir, 'baseline_%s.csv' % (cls))
with open(baselineFile, 'wb') as baseline:
csvWriter = csv.writer(baseline)
header = newBaseline[cls][testCases[0]].keys()
header = ['featureName'] + list(TEST_CASES)
csvWriter.writerow(header)
for testCase in testCases:
row = []
for h in header:
row += [newBaseline[cls][testCase][h]]

features = newBaseline[cls][TEST_CASES[0]].keys()
for f in features:
row = [f]
for testCase in TEST_CASES:
row.append(newBaseline[cls][testCase].get(f, ''))
csvWriter.writerow(row)
baseline.close()

Expand Down
38 changes: 32 additions & 6 deletions data/baseline/baseline_firstorder.csv
Original file line number Diff line number Diff line change
@@ -1,6 +1,32 @@
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,InterquartileRange,Skewness,Uniformity,MeanAbsoluteDeviation,Energy,RobustMeanAbsoluteDeviation,Median,TotalEnergy,Maximum,RootMeanSquared,90Percentile,Minimum,Entropy,StandardDeviation,Range,Variance,10Percentile,Kurtosis,Mean
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,253.0,0.27565085908587594,0.045156963555862184,133.44726195252767,33122817481.0,103.00138343026681,812.0,131407662125.54922,1266.0,2829.5728210757125,1044.4000000000001,468.0,4.6019355539037967,156.61123589440385,798.0,24527.079208372608,632.0,2.1807729393860265,825.23543630650227
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,97.0,0.4386372506317367,0.095965576558533008,73.554269062273107,2594007770.0,44.018676959200739,375.0,10291168521.118156,729.0,2392.9660398741912,532.60000000000002,8.0,3.8206001230555682,102.1243477592642,721.0,10429.38240525513,305.20000000000005,4.6747161961935264,390.78587196467993
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,30.0,0.041827973131320723,0.38901657782776666,13.93975255513717,649499543.0,11.083091863105961,130.0,601471983.42331111,162.0,2131.1862532762934,151.80000000000001,102.0,1.4490921348002006,16.042281168059137,60.0,257.35478507506485,110.2,1.8044408150083193,131.12587412587413
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,198.0,-0.73366595360417897,0.07442664462743856,105.09444751337841,3150327991.0,81.580905349794236,-31.0,5123320881.3595581,106.0,1940.0599797967793,71.0,-506.0,4.0208349271393855,124.01818919070283,612.0,15380.51125014096,-245.40000000000001,2.6959270958193589,-63.908004778972519
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,30.0,-3.0222132456965567,0.28153721195636616,59.581897780966464,99558480758.0,19.669786252104565,41.0,195667354538.98093,297.0,2009.9420229154007,60.700000000000728,-840.0,2.6529019354413741,96.957559721307049,1137.0,9400.7683871108238,-102.0,12.884706923906494,7.6020938159389706
featureName,brain1,brain2,breast1,lung1,lung2
general_info_TestCase,brain1,brain2,breast1,lung1,lung2
general_info_BoundingBox,"(162, 84, 11, 47, 70, 7)","(205, 155, 8, 20, 15, 3)","(21, 64, 8, 9, 12, 3)","(206, 347, 32, 24, 26, 3)","(318, 333, 15, 87, 66, 11)"
general_info_EnabledImageTypes,{'Original': {}},{'Original': {}},{'Original': {}},{'Original': {}},{'Original': {}}
general_info_GeneralSettings,"{'distances': [1], 'voxelArrayShift': 2000, 'additionalInfo': True, 'enableCExtensions': True, 'force2D': False, 'interpolator': None, 'resampledPixelSpacing': None, 'gldm_a': 0, 'weightingNorm': None, 'normalizeScale': 1, 'normalize': False, 'force2Ddimension': 0, 'removeOutliers': None, 'minimumROISize': None, 'binWidth': 25, 'label': 1, 'minimumROIDimensions': 1, 'preCrop': False, 'resegmentRange': None, 'padDistance': 5}","{'distances': [1], 'voxelArrayShift': 2000, 'additionalInfo': True, 'enableCExtensions': True, 'force2D': False, 'interpolator': None, 'resampledPixelSpacing': None, 'gldm_a': 0, 'weightingNorm': None, 'normalizeScale': 1, 'normalize': False, 'force2Ddimension': 0, 'removeOutliers': None, 'minimumROISize': None, 'binWidth': 25, 'label': 1, 'minimumROIDimensions': 1, 'preCrop': False, 'resegmentRange': None, 'padDistance': 5}","{'distances': [1], 'voxelArrayShift': 2000, 'additionalInfo': True, 'enableCExtensions': True, 'force2D': False, 'interpolator': None, 'resampledPixelSpacing': None, 'gldm_a': 0, 'weightingNorm': None, 'normalizeScale': 1, 'normalize': False, 'force2Ddimension': 0, 'removeOutliers': None, 'minimumROISize': None, 'binWidth': 25, 'label': 1, 'minimumROIDimensions': 1, 'preCrop': False, 'resegmentRange': None, 'padDistance': 5}","{'distances': [1], 'voxelArrayShift': 2000, 'additionalInfo': True, 'enableCExtensions': True, 'force2D': False, 'interpolator': None, 'resampledPixelSpacing': None, 'gldm_a': 0, 'weightingNorm': None, 'normalizeScale': 1, 'normalize': False, 'force2Ddimension': 0, 'removeOutliers': None, 'minimumROISize': None, 'binWidth': 25, 'label': 1, 'minimumROIDimensions': 1, 'preCrop': False, 'resegmentRange': None, 'padDistance': 5}","{'distances': [1], 'voxelArrayShift': 2000, 'additionalInfo': True, 'enableCExtensions': True, 'force2D': False, 'interpolator': None, 'resampledPixelSpacing': None, 'gldm_a': 0, 'weightingNorm': None, 'normalizeScale': 1, 'normalize': False, 'force2Ddimension': 0, 'removeOutliers': None, 'minimumROISize': None, 'binWidth': 25, 'label': 1, 'minimumROIDimensions': 1, 'preCrop': False, 'resegmentRange': None, 'padDistance': 5}"
general_info_ImageHash,5c9ce3ca174f0f8324aa4d277e0fef82dc5ac566,f2b8fbc4d5d1da08a1a70e79a301f8a830139438,016951a8f9e8e5de21092d9d62b77262f92e04a5,34dca4200809a5e76c702d6b9503d958093057a3,14f57fd04838eb8c9cca2a0dd871d29971585975
general_info_ImageSpacing,"(0.7812499999999999, 0.7812499999999999, 6.499999999999998)","(0.7812499999999999, 0.7812499999999999, 6.499999999999998)","(0.664062, 0.664062, 2.1)","(0.5703125, 0.5703125, 5.0)","(0.6269531, 0.6269531, 5.0)"
general_info_MaskHash,9dc2c3137b31fd872997d92c9a92d5178126d9d3,b41049c71633e194bee4891750392b72eabd8800,5aa7d57fd57e83125b605c036c40f4a0d0cfd3e4,054d887740012177bd1f9031ddac2b67170af0f3,e284ff05593bc6cb2747261882e452d4efbccb3a
general_info_NumpyVersion,1.14.0,1.14.0,1.14.0,1.14.0,1.14.0
general_info_PyWaveletVersion,0.5.2,0.5.2,0.5.2,0.5.2,0.5.2
general_info_SimpleITKVersion,0.9.1,0.9.1,0.9.1,0.9.1,0.9.1
general_info_Version,1.3.0.post61.dev0+gec8ca3f,1.3.0.post61.dev0+gec8ca3f,1.3.0.post61.dev0+gec8ca3f,1.3.0.post61.dev0+gec8ca3f,1.3.0.post61.dev0+gec8ca3f
general_info_VolumeNum,2,1,1,1,1
general_info_VoxelNum,4137,453,143,837,24644
original_firstorder_InterquartileRange,253.0,97.0,30.0,198.0,30.0
original_firstorder_Skewness,0.27565085908587594,0.4386372506317367,0.04182797313132072,-0.733665953604179,-3.0222132456965567
original_firstorder_Uniformity,0.045156963555862184,0.09596557655853301,0.38901657782776666,0.07442664462743856,0.28153721195636616
original_firstorder_Median,812.0,375.0,130.0,-31.0,41.0
original_firstorder_Energy,33122817481.0,2594007770.0,649499543.0,3150327991.0,99558480758.0
original_firstorder_RobustMeanAbsoluteDeviation,103.00138343026681,44.01867695920074,11.083091863105961,81.58090534979424,19.669786252104565
original_firstorder_MeanAbsoluteDeviation,133.44726195252767,73.55426906227311,13.93975255513717,105.09444751337841,59.581897780966464
original_firstorder_TotalEnergy,131407662125.54922,10291168521.118156,601471983.4233111,5123320881.359558,195667354538.98093
original_firstorder_Maximum,1266.0,729.0,162.0,106.0,297.0
original_firstorder_RootMeanSquared,2829.5728210757125,2392.966039874191,2131.1862532762934,1940.0599797967793,2009.9420229154007
original_firstorder_90Percentile,1044.4,532.6,151.8,71.0,60.70000000000073
original_firstorder_Minimum,468.0,8.0,102.0,-506.0,-840.0
original_firstorder_Entropy,4.601935553903797,3.820600123055568,1.4490921348002006,4.0208349271393855,2.652901935441374
original_firstorder_Range,798.0,721.0,60.0,612.0,1137.0
original_firstorder_Variance,24527.07920837261,10429.38240525513,257.35478507506485,15380.51125014096,9400.768387110824
original_firstorder_10Percentile,632.0,305.20000000000005,110.2,-245.4,-102.0
original_firstorder_Kurtosis,2.1807729393860265,4.674716196193526,1.8044408150083193,2.695927095819359,12.884706923906494
original_firstorder_Mean,825.2354363065023,390.7858719646799,131.12587412587413,-63.90800477897252,7.602093815938971
Loading

0 comments on commit 617ddcc

Please sign in to comment.