├── logs ├── eval.indicesadded.log~ ├── eval.stdsettings.log~ ├── exp0.f_flair.log ├── eval.indicesadded.log ├── et_rdf_alter.log.old ├── exp00.k.log ├── eval.rdf.all.log ├── exp00.k.log~ ├── eval.shifted_gauss.log ├── exp00.g.log ├── exp00.h.log ├── eval.condnodes.0.05.log ├── eval.rdf.all.depth9.log ├── et_rdf_alter.log ├── et_rdf_alter.log~ ├── exp00.j.log ├── exp00.e.log ├── exp00.i.log ├── exp00.b.log ├── exp00.f.log ├── exp01.b.thr1000.log ├── exp01.b.thr2000.log ├── exp01.b.thr250.log ├── exp01.b.thr500.log ├── exp01.b.thr750.log ├── exp00.a.log ├── exp00.a.log~ ├── exp01.b.thr1500.log ├── eval.all.momentnormalization.log └── eval.all.momentnormalization.log~ ├── LICENSE ├── README.md ├── joinforests.py ├── analyzeforest.py ├── documentation ├── description ├── Ideas.odt ├── imageflow.dia ├── imageflow.pdf ├── Brainextraction.odt ├── rdfsegmentation.dia ├── Biasfieldcorrection.odt ├── intersequenceregistration ├── UnivariateFeatureSelectionStatistics.odt ├── HemisphericDifferenceFeature_NotesOnEnhancements.odt ├── t2space ├── biasfieldcorrection ├── stdspace ├── cmtk_tools └── niftimetadata ├── 00original ├── GROUPINGS.ods ├── IMAGESELECTION.ods ├── IMAGECHARACTERISTICS_COMBINED.ods ├── description ├── IMAGECHARACTERISTICS_RANKED.csv └── GROUPINGS ├── experiments ├── Documentation.odt ├── Documentation.exp00.odt ├── Documentation.exp01.odt ├── Evaluation.BestCombination.ods ├── MixedNodeForestsEvaluation ├── 05flairlesionsegmentation ├── exp01a.cycle01.description ├── RemarksOnWorstCases ├── ParallelTreesAndAlternatingNodeMixedForests └── RDF_ET_BehaviourInTheFirstFewLayers ├── scripts ├── clean.py ├── tofloat64.py ├── threshold.py ├── thresholdcondenseimage.py ├── invert.py ├── correct_sform.py ├── condenseoutliers.py ├── apply_binary_mask.py ├── brainmasksegmcutoff.py ├── pass_header.py ├── show.sh ├── flip.py ├── naive_intensity_std.py ├── remove_small_objects.py ├── joinmarker.py ├── compute_lesion_volumes.py ├── check_spm_normalize_estimate_log.py ├── evaluate_mi.py ├── info.py ├── align.py ├── make_spm_normalize_write.py ├── make_spm_normalize_write_mask.py ├── morphology.py ├── equalvs.py ├── make_spm_normalize_estimate.py ├── niftimodifymetadata.py ├── train_rdf.py ├── make_spm_segment.py ├── extract_features.py ├── parse_time.py ├── colourconfig.py ├── extract_features_sequencespace.py ├── apply_rdf.py ├── sample_trainingset.alternative.py ├── extract_features_stdspace.py ├── evaluate_segmentations.py ├── ttest.py ├── evaluate_stdspace.py └── parse_excluding.py ├── evaluate.sh ├── pop_sequencetrainforests.sh ├── pop_sequencefeatures.sh ├── eva_sequencespace.sh ├── pop_sequencesamplesets.sh ├── pop_sequencebiasfieldcorrected.sh ├── experiments.txt ├── pop_sequencelesionsegmentation.sh ├── evaluate_original.sh ├── metadata.py ├── .gitignore ├── clone.sh ├── config.sh ├── pop_sequenceskullstripped.sh ├── pop_segmentations.sh ├── pop_sequenceintensitrangestandardization.sh ├── pop_sequencesegmentations.sh ├── pop_original.sh └── pop_sequencespace.sh /logs/eval.indicesadded.log~: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /logs/eval.stdsettings.log~: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | non-public repository 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | neuropipeline 2 | ============= 3 | a saveguard 4 | -------------------------------------------------------------------------------- /joinforests.py: -------------------------------------------------------------------------------- 1 | /home/maier/Workspacepython/medpy/bin/others/joinforests.py -------------------------------------------------------------------------------- /analyzeforest.py: -------------------------------------------------------------------------------- 1 | /home/maier/Workspacepython/medpy/bin/others/analyzeforest.py -------------------------------------------------------------------------------- /documentation/description: -------------------------------------------------------------------------------- 1 | Contains the detailed descriptions of each of the pipelines steps. 2 | -------------------------------------------------------------------------------- /00original/GROUPINGS.ods: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loli/nspipeline/master/00original/GROUPINGS.ods -------------------------------------------------------------------------------- /documentation/Ideas.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loli/nspipeline/master/documentation/Ideas.odt -------------------------------------------------------------------------------- /documentation/imageflow.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loli/nspipeline/master/documentation/imageflow.dia -------------------------------------------------------------------------------- /documentation/imageflow.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loli/nspipeline/master/documentation/imageflow.pdf -------------------------------------------------------------------------------- /00original/IMAGESELECTION.ods: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loli/nspipeline/master/00original/IMAGESELECTION.ods -------------------------------------------------------------------------------- /experiments/Documentation.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loli/nspipeline/master/experiments/Documentation.odt -------------------------------------------------------------------------------- /documentation/Brainextraction.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loli/nspipeline/master/documentation/Brainextraction.odt -------------------------------------------------------------------------------- /documentation/rdfsegmentation.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loli/nspipeline/master/documentation/rdfsegmentation.dia -------------------------------------------------------------------------------- /experiments/Documentation.exp00.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loli/nspipeline/master/experiments/Documentation.exp00.odt -------------------------------------------------------------------------------- /experiments/Documentation.exp01.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loli/nspipeline/master/experiments/Documentation.exp01.odt -------------------------------------------------------------------------------- /documentation/Biasfieldcorrection.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loli/nspipeline/master/documentation/Biasfieldcorrection.odt -------------------------------------------------------------------------------- /documentation/intersequenceregistration: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loli/nspipeline/master/documentation/intersequenceregistration -------------------------------------------------------------------------------- /experiments/Evaluation.BestCombination.ods: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loli/nspipeline/master/experiments/Evaluation.BestCombination.ods -------------------------------------------------------------------------------- /00original/IMAGECHARACTERISTICS_COMBINED.ods: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loli/nspipeline/master/00original/IMAGECHARACTERISTICS_COMBINED.ods -------------------------------------------------------------------------------- /logs/exp0.f_flair.log: -------------------------------------------------------------------------------- 1 | INFO: Reverting segmentations.... 2 | INFO: Evaluating in original space... 3 | INFO: Evaluating in sequence space.. 4 | -------------------------------------------------------------------------------- /logs/eval.indicesadded.log: -------------------------------------------------------------------------------- 1 | INFO: Reverting segmentations.... 2 | INFO: Evaluating in original space... 3 | INFO: Evaluating in sequence space.. 4 | -------------------------------------------------------------------------------- /documentation/UnivariateFeatureSelectionStatistics.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loli/nspipeline/master/documentation/UnivariateFeatureSelectionStatistics.odt -------------------------------------------------------------------------------- /documentation/HemisphericDifferenceFeature_NotesOnEnhancements.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loli/nspipeline/master/documentation/HemisphericDifferenceFeature_NotesOnEnhancements.odt -------------------------------------------------------------------------------- /documentation/t2space: -------------------------------------------------------------------------------- 1 | All sequences are rigidly registered to the T2 volume. 2 | 3 | Since DW and ADC share the same space, only one of these spectra has to be registered. We empirically chose DW for the registration, as random samples have shown the ADC based registration to be severly off in some cases (e.g. 13). 4 | -------------------------------------------------------------------------------- /scripts/clean.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # clean out nan and inf values in-place. 4 | # arg1: the image to clean 5 | 6 | import sys 7 | 8 | import numpy 9 | 10 | from medpy.io import load, save 11 | 12 | i, h = load(sys.argv[1]) 13 | 14 | i[numpy.isnan(i)] = 0 15 | i[numpy.isinf(i)] = 0 16 | 17 | i = i.copy() 18 | 19 | save(i, sys.argv[1], h) 20 | -------------------------------------------------------------------------------- /scripts/tofloat64.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | """ 4 | Load the input image, convert its data to numpy.float64, then save it under output. 5 | """ 6 | 7 | import sys 8 | import numpy 9 | from medpy.io import load, save 10 | 11 | def main(): 12 | i, h = load(sys.argv[1]) 13 | save(i.astype(numpy.float64), sys.argv[2], h) 14 | 15 | if __name__ == "__main__": 16 | main() 17 | 18 | 19 | -------------------------------------------------------------------------------- /scripts/threshold.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | """ 4 | Thresholds an image according to a value (True where intensity >= value). 5 | arg1: the input image 6 | arg2: the threshold 7 | arg3: the output image 8 | """ 9 | 10 | import sys 11 | import numpy 12 | 13 | from medpy.io import load, save 14 | 15 | def main(): 16 | i, h = load(sys.argv[1]) 17 | thr = float(sys.argv[2]) 18 | 19 | o = i >= thr 20 | 21 | save(o, sys.argv[3], h) 22 | 23 | if __name__ == "__main__": 24 | main() 25 | -------------------------------------------------------------------------------- /evaluate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #### 4 | # Evaluate the results of a segmentation 5 | #### 6 | 7 | # include shared information 8 | source $(dirname $0)/include.sh 9 | 10 | # main code 11 | log 2 "Compute overall evaluation" "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 12 | runcond "${scripts}/evaluate_segmentations.py ${sequencelesionsegmentation}/{}/segmentation_post.${imgfiletype} ${sequencesegmentations}/{}.${imgfiletype} ${sequencebrainmasks}/{}.${imgfiletype} $(joinarr " " ${images[@]})" 13 | 14 | -------------------------------------------------------------------------------- /scripts/thresholdcondenseimage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | """ 4 | Apply a lower threshold to an image and condense all intensities below to the threshold value. 5 | .py 6 | """ 7 | 8 | import sys 9 | import numpy 10 | from medpy.io import load, save 11 | 12 | def main(): 13 | i, h = load(sys.argv[1]) 14 | thr = int(sys.argv[2]) 15 | i[i < thr] = thr 16 | save(i, sys.argv[3], h) 17 | 18 | if __name__ == "__main__": 19 | main() 20 | 21 | 22 | -------------------------------------------------------------------------------- /scripts/invert.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | #### 4 | # Inverts a binary image 5 | # arg1: the input image to invert 6 | # arg2: the inverted output image 7 | #### 8 | 9 | import sys 10 | 11 | import numpy 12 | 13 | from medpy.io import load, save 14 | 15 | def main(): 16 | infile = sys.argv[1] 17 | outfile = sys.argv[2] 18 | 19 | i, h = load(infile) 20 | i = i.astype(numpy.bool) 21 | h.set_sform(h.get_qform()) 22 | save(~i, outfile, h) 23 | 24 | if __name__ == "__main__": 25 | main() 26 | -------------------------------------------------------------------------------- /scripts/correct_sform.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | """ 4 | Corrects a (possibly) wrong sform in a NifTi header by copying the qform to it, 5 | arg1: the image to correct 6 | arg2: the target output image 7 | """ 8 | 9 | import sys 10 | 11 | from medpy.io import load, save 12 | 13 | def main(): 14 | # load input image 15 | i, h = load(sys.argv[1]) 16 | 17 | # correct sfrom 18 | h.set_sform(h.get_qform()) 19 | 20 | # save 21 | save(i, sys.argv[2], h) 22 | 23 | if __name__ == "__main__": 24 | main() 25 | -------------------------------------------------------------------------------- /scripts/condenseoutliers.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | """ 4 | Apply a percentile threshold to the image, condensing all outliers to the percentile values. 5 | .py 6 | """ 7 | 8 | import sys 9 | import numpy 10 | from medpy.io import load, save 11 | 12 | def main(): 13 | i, h = load(sys.argv[1]) 14 | li = numpy.percentile(i, (1, 99.9)) 15 | i[i < li[0]] = li[0] 16 | i[i > li[1]] = li[1] 17 | save(i, sys.argv[2], h) 18 | 19 | if __name__ == "__main__": 20 | main() 21 | 22 | 23 | -------------------------------------------------------------------------------- /scripts/apply_binary_mask.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | """ 4 | Apply a binary mask to an image, keeping only the intensity values where the maks is True. 5 | All other are set to zero. 6 | .py 7 | """ 8 | 9 | import sys 10 | import numpy 11 | from medpy.io import load, save 12 | 13 | def main(): 14 | i, h = load(sys.argv[1]) 15 | m = load(sys.argv[2])[0].astype(numpy.bool) 16 | i[~m] = 0 17 | save(i, sys.argv[3], h) 18 | 19 | if __name__ == "__main__": 20 | main() 21 | 22 | 23 | -------------------------------------------------------------------------------- /pop_sequencetrainforests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ##### 4 | # Train the decision forest with a training sample set. 5 | ##### 6 | 7 | ## Changelog 8 | # 2013-05-08 created 9 | 10 | # include shared information 11 | source $(dirname $0)/include.sh 12 | 13 | # main code 14 | log 2 "Training random decision forests" "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 15 | for i in "${images[@]}"; do 16 | runcond "scripts/train_rdf.py ${sequencesamplesets}/${i}/trainingset.features.npy ${sequenceforests}/${i}.pkl ${maxdepth}" 17 | done 18 | log 2 "Done." "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 19 | -------------------------------------------------------------------------------- /scripts/brainmasksegmcutoff.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | """ 4 | Takes a brain mask and a segmentation as input and checks, whether and if, how many voxel the brain mask cuts from the segmentation. 5 | """ 6 | 7 | import sys 8 | import numpy 9 | from medpy.io import load, save 10 | 11 | def main(): 12 | m = load(sys.argv[1])[0].astype(numpy.bool) 13 | s = load(sys.argv[2])[0].astype(numpy.bool) 14 | 15 | intc = numpy.count_nonzero(~m & s) 16 | 17 | print "Non-intersecting part of the segmentation:" 18 | print "{} out of {} voxels".format(intc, numpy.count_nonzero(s)) 19 | 20 | if __name__ == "__main__": 21 | main() 22 | 23 | 24 | -------------------------------------------------------------------------------- /scripts/pass_header.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | """ 4 | Passes a header from one image file to another (with the usual adaptions of data type, etc. undetaken). 5 | arg1: the image to correct (in-place) 6 | arg2: the template image, whose header to take 7 | """ 8 | 9 | import sys 10 | import numpy 11 | 12 | from medpy.io import load, save 13 | 14 | def main(): 15 | # load input image 16 | i, _ = load(sys.argv[1]) 17 | 18 | # load template image 19 | _, h = load(sys.argv[2]) 20 | 21 | # save input image with adapted header in place 22 | j = i.copy() 23 | save(j, sys.argv[1], h) 24 | 25 | if __name__ == "__main__": 26 | main() 27 | 28 | -------------------------------------------------------------------------------- /scripts/show.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ###### 4 | # Displays the .nii.gz images in the supplied location with amide. 5 | ###### 6 | 7 | # changelog 8 | # 2013-11-11 created 9 | 10 | echo "Displaying images from ${i} with amide:" 11 | 12 | tmpdir=`mktemp -d` 13 | echo "Using temporary directory ${tmpdir}..." 14 | 15 | echo "Unpacking images..." 16 | for f in "${1}"/*.nii.gz; do 17 | fn=`basename $f .nii.gz` 18 | medpy_convert.py "${f}" "${tmpdir}/${fn}.nii" 19 | done 20 | 21 | echo "Displaying images..." 22 | amide ${tmpdir}/t2_sag_tse.nii ${tmpdir}/*.nii ${tmpdir}/*.nii 23 | 24 | echo "Cleaning up..." 25 | rm ${tmpdir}/* 26 | rmdir ${tmpdir} 27 | echo "done." 28 | 29 | -------------------------------------------------------------------------------- /scripts/flip.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | #### 4 | # Flips an image along the given dimensions in-place. 5 | # arg1: the image to flip 6 | # arg2: the dimension along which to flip 7 | #### 8 | 9 | import sys 10 | 11 | import numpy 12 | 13 | from medpy.io import load, save 14 | 15 | def main(): 16 | _file = sys.argv[1] 17 | dim = int(sys.argv[2]) 18 | 19 | i, h = load(_file) 20 | i = flip_axis(i, dim).copy() 21 | save(i, _file, h) 22 | 23 | def flip_axis(arr, axis=0): 24 | arr = numpy.asanyarray(arr) 25 | arr = arr.swapaxes(0, axis) 26 | arr = numpy.flipud(arr) 27 | return arr.swapaxes(axis, 0) 28 | 29 | if __name__ == "__main__": 30 | main() 31 | -------------------------------------------------------------------------------- /pop_sequencefeatures.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ##### 4 | # Extracts a number of features as defined in a python-style config file. 5 | ##### 6 | 7 | ## Changelog 8 | # 2013-05-08 created 9 | 10 | # include shared information 11 | source $(dirname $0)/include.sh 12 | 13 | # main code 14 | log 2 "Extracting the features" "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 15 | function extract_features () 16 | { 17 | i=$1 18 | mkdircond ${sequencefeatures}/${i} 19 | runcond "${scripts}/extract_features.py ${sequenceintensitrangestandardization}/${i}/ ${sequencebrainmasks}/${i}.${imgfiletype} ${sequencefeatures}/${i}/ ${featurecnf}" 20 | } 21 | parallelize extract_features ${threadcount} images[@] 22 | log 2 "Done." "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 23 | -------------------------------------------------------------------------------- /scripts/naive_intensity_std.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # normalizes an images intensities by zero mean and unit variance 4 | # normalizes an images intensities by zero modus and unit variance 5 | # arg1: the image to normalize 6 | # arg2: the image mask 7 | # arg3: the normalized image 8 | 9 | import sys 10 | import numpy 11 | 12 | from medpy.io import load, save 13 | 14 | i, h = load(sys.argv[1]) 15 | m = load(sys.argv[2])[0].astype(numpy.bool) 16 | 17 | #i -= i.mean() 18 | #i /= i.std() 19 | 20 | hist, bin_edges = numpy.histogram(i[m], bins=100) 21 | modus_pos = numpy.argmax(hist) 22 | lower, upper = bin_edges[modus_pos:modus_pos+2] 23 | modus = (upper - lower) / 2. 24 | 25 | i[m] -= modus 26 | i[m] /= i.std() 27 | 28 | save(i, sys.argv[3], h) 29 | -------------------------------------------------------------------------------- /logs/et_rdf_alter.log.old: -------------------------------------------------------------------------------- 1 | Metrics: 2 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 3 | 03 0.784 31.464 4.194 0.955 0.665 4 | 05 0.628 24.187 6.961 0.997 0.458 5 | 07 0.887 13.748 1.736 0.945 0.835 6 | 09 0.683 10.392 2.160 0.801 0.595 7 | 10 0.577 26.325 6.227 0.975 0.409 8 | 11 0.545 28.460 4.479 0.909 0.389 9 | 12 0.799 24.556 3.103 0.954 0.687 10 | 13 0.848 22.450 2.525 0.873 0.825 11 | 15 0.810 11.225 2.230 0.744 0.890 12 | DM average 0.729022712393 +/- 0.116863474967 (Median: 0.783839457771) 13 | HD average 21.4230486134 +/- 7.28374821834 (Median: 24.1867732449) 14 | ASSD average 3.73497668983 +/- 1.76344566554 (Median: 3.10330283165) 15 | Prec. average 0.906054418591 +/- 0.0801092619555 (Median: 0.945259593679) 16 | Rec. average 0.639303346209 +/- 0.179001319346 (Median: 0.664563380282) 17 | -------------------------------------------------------------------------------- /eva_sequencespace.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ##### 4 | # Roughly evaluates the results of the registration to t2space. 5 | # This evaluation is not very informative, but might serve to detect failed registrations. 6 | ##### 7 | 8 | ## Changelog 9 | # 2013-11-11 created 10 | 11 | # include shared information 12 | source $(dirname $0)/include.sh 13 | 14 | # main code 15 | log 2 "Evaluating against T2" "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 16 | for s in "${sequences[@]}"; do 17 | 18 | echo "image;mu" > ${t2space}/${s}.againstt2.eval.csv 19 | 20 | log 2 "Processing sequence ${s}" "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 21 | for i in "${images[@]}"; do 22 | cmd="${scripts}/evaluate_mi.py ${t2space}/${i}/${s}.${imgfiletype} ${t2space}/${i}/t2_sag_tse.${imgfiletype}" 23 | $cmd >> ${t2space}/${s}.againstt2.eval.csv 24 | done 25 | done 26 | -------------------------------------------------------------------------------- /pop_sequencesamplesets.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ##### 4 | # Samples a number of training samples randomly using a set of selected features. 5 | ##### 6 | 7 | ## Changelog 8 | # 2013-05-08 created 9 | 10 | # include shared information 11 | source $(dirname $0)/include.sh 12 | 13 | # main code 14 | log 2 "Drawing a training set for each leave-one-out case using stratified random sampling" "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 15 | function sample_trainingset () 16 | { 17 | local i=$1 18 | mkdircond ${sequencesamplesets}/${i} 19 | local _images=( $(delEl "${i}" images[@]) ) 20 | runcond "${scripts}/sample_trainingset.py ${sequencefeatures}/ ${sequencesegmentations}/ ${sequencebrainmasks}/ ${sequencesamplesets}/${i}/ ${featurecnf} ${samplesize} $(joinarr " " ${_images[@]})" 21 | } 22 | parallelize sample_trainingset ${threadcount} images[@] 23 | log 2 "Done." "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 24 | -------------------------------------------------------------------------------- /00original/description: -------------------------------------------------------------------------------- 1 | Holds the original images, some as softlinks, other as real files. One sub-folder per 2 | case, each with a different number of image files. 3 | 4 | The cases come from two different sources, the HEOPKS and JGABLENTZ image collections, 5 | but they all depict ischemic stroke lesions (although sometimes with small hemorrhages 6 | included). 7 | 8 | Image characteristics are listed in "IMAGECHARACTERISTICS_COMBINED.ods". 9 | Selection of cases and the mapping from database to case id are in "IMAGESELECTION.ods". 10 | Groupings according to different selection criteria can be found in "GROUPINGS.ods". 11 | 12 | All image with their original size, spacing and datatype. 13 | 14 | All lesions are left-sided. For balancing reasons, every second case is flipped along the 15 | mid-saggital plane to mimic a right-sided stroke. This is noted in 16 | "IMAGECHARACTERISTICS_COMBINED.ods". 17 | -------------------------------------------------------------------------------- /scripts/remove_small_objects.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | """ 4 | Remove small binary objects from a binary mask. 5 | Note: Takes voxel-spacing into account. 6 | Note: Does not remove small objects if hte binary mask would be empty afterwards. 7 | .py 8 | """ 9 | 10 | import sys 11 | import numpy 12 | from medpy.io import load, save, header 13 | from medpy.filter import size_threshold 14 | 15 | def main(): 16 | thr = float(sys.argv[3]) 17 | i, h = load(sys.argv[1]) 18 | 19 | # adapt threshold by voxel spacing 20 | thr /= numpy.prod(header.get_pixel_spacing(h)) 21 | # threshold binary objects 22 | j = size_threshold(i, thr, 'lt') 23 | # reset if last object has been removed 24 | if 0 == numpy.count_nonzero(j): 25 | j = i 26 | 27 | save(j, sys.argv[2], h, True) 28 | 29 | if __name__ == "__main__": 30 | main() 31 | 32 | 33 | -------------------------------------------------------------------------------- /documentation/biasfieldcorrection: -------------------------------------------------------------------------------- 1 | 2 | Note: it seems that most tools (like imiLib and FSL) work better when the skull has been stripped before. 3 | 4 | Note: the bias fields produced by the tools differ greatly; how to determine the best one? 5 | 6 | Using CMTK 7 | ########## 8 | Tested on two T2 volumes (03 + 06) with skull present. 9 | The results are promising, with a long (20+min) runtime. 10 | 11 | Tested on two T2 volumes (04 + 12) with skull absent. 12 | The results are promising, with a long (20+min) runtime. 13 | 14 | Using imiLib 15 | ############ 16 | Tested on two T2 volumes (03 + 06) with skull present. 17 | The results are promising, with a medium runtime (~3min). 18 | 19 | Tested on two T2 volumes (04 + 12) with skull absent. 20 | The results are promising, with a medium runtime (~3min). 21 | 22 | Using FSL (FAST) 23 | ################ 24 | Tested on two T2 volumes (03 + 06) with skull present. 25 | The results are promising, with a long (20+min) runtime. 26 | -------------------------------------------------------------------------------- /scripts/joinmarker.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | """ 4 | Joins a number of binary masks into an single uint file with consecutive numbers. Where 5 | intersection occurs, the higer numbers are given priority. 6 | """ 7 | 8 | # build-in modules 9 | import sys 10 | 11 | # third-party modules 12 | import numpy 13 | 14 | # path changes 15 | 16 | # own modules 17 | from medpy.io import load, save 18 | 19 | # information 20 | 21 | # code 22 | def main(): 23 | output_file = sys.argv[1] 24 | input_files = sys.argv[2:] 25 | 26 | mask_identifier = 1 27 | 28 | output_data, output_header = load(input_files[0]) 29 | output_data = output_data.astype(numpy.uint8) 30 | output_data[output_data > 0] = mask_identifier 31 | 32 | 33 | for input_file in input_files[1:]: 34 | mask_identifier += 1 35 | input_data, _ = load(input_file) 36 | output_data[input_data > 0] = mask_identifier 37 | 38 | save(output_data, output_file, output_header, True) 39 | 40 | 41 | if __name__ == "__main__": 42 | main() 43 | -------------------------------------------------------------------------------- /experiments/MixedNodeForestsEvaluation: -------------------------------------------------------------------------------- 1 | Description 2 | ########### 3 | Together with Michael from Heidelberg, I devised four Mixed Node Forests types 4 | AlternatingNode-TreeClassifier 5 | AdaptiveNode- 6 | RandomNode- 7 | StackedNode- 8 | which we tested on a number of standard classification datasets and compared agains RDF and ET in various configurations. 9 | 10 | Location 11 | ######## 12 | /data_humbug1/maier/Temp_Playground/mixednodeforests 13 | 14 | Conclusion 15 | ########## 16 | The observations made in the ET paper by Geurts et al. could largely be confirmed. 17 | Our AlternatingNode method performed en-pa with the ETs and better than the RDFs. 18 | Our other methods performed laregly worse than the ETs, more along the line of the RDFs. 19 | For some few problems the RDF outperformed the ET. In these cases, the AlternatingNode method didn't suffer the same drop in accuracy as the ET i.e. they mght be slightly more robust. 20 | 21 | Overall, it sadly has to be said that our methods did not lead to any real improvement on the problems to which we applied them. 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /scripts/compute_lesion_volumes.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | """ 4 | Computes the lesion volumes, once percentual to the brain volume and once in mm, and 5 | prints them to the stdout. 6 | 7 | arg1: the directory with the lesion mask images 8 | arg2: the directory with the brain mask images 9 | """ 10 | 11 | import os 12 | import sys 13 | 14 | import numpy 15 | 16 | from medpy.io import load, header 17 | 18 | def main(): 19 | print 'lesion\tvolume (%)\tvolume (mm)' 20 | 21 | files = [f for f in os.listdir('{}'.format(sys.argv[1])) if os.path.isfile('{}/{}'.format(sys.argv[1], f))] 22 | for f in files: 23 | l, h = load('{}/{}'.format(sys.argv[1], f)) 24 | m, _ = load('{}/{}'.format(sys.argv[2], f)) 25 | 26 | lesion_voxel = numpy.count_nonzero(l) 27 | total_voxel = numpy.count_nonzero(m) 28 | 29 | volume_mm = numpy.prod(header.get_pixel_spacing(h)) * lesion_voxel 30 | volume_percentage = lesion_voxel / float(total_voxel) 31 | 32 | print '{}\t{}\t{}\t'.format(f[:-7], volume_percentage, volume_mm) 33 | 34 | if __name__ == "__main__": 35 | main() 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /scripts/check_spm_normalize_estimate_log.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | #### 4 | # Checks a the output created by a SPM Normalize Estimate operation for potentially failed registrations. If detected, prints a warning. 5 | # arg1: the log file containing the output 6 | # arg2: the FWHM score threshold 7 | #### 8 | 9 | import sys 10 | 11 | def main(): 12 | logfile = sys.argv[1] 13 | fwhm_threshold = float(sys.argv[2]) 14 | 15 | with open(logfile, 'r') as f: 16 | fwhm_found = False 17 | for line in f.readlines(): 18 | line = line.strip() 19 | if 'FWHM' in line: 20 | fwhm_found = True 21 | segments = line.split('=') 22 | fwhm_value = float(segments[1].strip().split(' ')[0]) 23 | fwhm_std = float(segments[2].strip().split(' ')[0]) 24 | elif fwhm_found: 25 | print 'Registration terminated with FWHM {} +/- {}.'.format(fwhm_value, fwhm_std) 26 | if fwhm_value > fwhm_threshold: 27 | print 'WARNING: Registration terminated with a score FWHM value of {}, which is above the threshold {}.'.format(fwhm_value, fwhm_threshold) 28 | fwhm_found = False 29 | 30 | if __name__ == "__main__": 31 | main() 32 | -------------------------------------------------------------------------------- /scripts/evaluate_mi.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | """ 4 | Mutual information evaluation. 5 | arg1: first image 6 | arg2: second image 7 | """ 8 | 9 | import sys 10 | 11 | import numpy 12 | 13 | from medpy.io import load, save 14 | from medpy.metric.image import mutual_information 15 | 16 | def main(): 17 | # load input images 18 | i1, h1 = load(sys.argv[1]) 19 | i2, h2 = load(sys.argv[2]) 20 | 21 | # clean images 22 | i1 = clean(i1) 23 | i2 = clean(i2) 24 | 25 | # smooth images 26 | #i1 = gauss(i1, h1, sigma=2) 27 | #i2 = gauss(i2, h2, sigma=2) 28 | 29 | # mutual information 30 | mu = mutual_information(i1[(i1 > 0) & (i2 > 0)], i2[(i1 > 0) & (i2 > 0)]) 31 | 32 | # print 33 | print '{};{};'.format(sys.argv[1], mu) 34 | 35 | def clean(i, cval = 0): 36 | """ 37 | Removes all nan and inf from the image and replace them with a constant value. 38 | """ 39 | i[numpy.isnan(i)] = 0 40 | i[numpy.isinf(i)] = 0 41 | return i 42 | 43 | def gauss(i, h, sigma=6): 44 | """ 45 | Applies a gaussian smoothing to the image with the supplied kernel size in mmm. 46 | """ 47 | sigmas = [sigma * ps for ps in header.get_pixel_spacing(h)] 48 | i = gaussian_filter(i, sigma=sigmas) 49 | return i 50 | 51 | if __name__ == "__main__": 52 | main() 53 | -------------------------------------------------------------------------------- /pop_sequencebiasfieldcorrected.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ##### 4 | # Removes intensity in-homogenities in the images. 5 | ##### 6 | 7 | ## Changelog 8 | # 2014-04-09 adapted to new style 9 | # 2013-11-14 added a step to correct the nifti metadata 10 | # 2013-11-04 imporved code 11 | # 2013-10-17 created 12 | 13 | # include shared information 14 | source $(dirname $0)/include.sh 15 | 16 | # main code 17 | log 2 "Correcting the bias fields" "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 18 | for i in "${images[@]}"; do 19 | mkdircond ${sequencebiasfieldcorrected}/${i} 20 | for s in "${sequences[@]}"; do 21 | 22 | # continue if target file already exists 23 | if [ -f "${sequencebiasfieldcorrected}/${i}/${s}.${imgfiletype}" ]; then 24 | continue 25 | fi 26 | 27 | # esitmate and correct bias field 28 | runcond "cmtk mrbias --mask ${sequencebrainmasks}/${i}.${imgfiletype} ${sequenceskullstripped}/${i}/${s}.${imgfiletype} ${sequencebiasfieldcorrected}/${i}/${s}.${imgfiletype}" # note: already multitasking 29 | 30 | # correct nifit orientation metadata in-place 31 | runcond "${scripts}/niftimodifymetadata.py ${sequencebiasfieldcorrected}/${i}/${s}.${imgfiletype} qf=aff sf=aff qfc=1 sfc=1" 32 | done 33 | done 34 | log 2 "Done." "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 35 | 36 | -------------------------------------------------------------------------------- /experiments.txt: -------------------------------------------------------------------------------- 1 | Preparation 2 | ########### 3 | Flip every second lesion from left to right and remoark in CHARACTERISTICS, whoch ones have been flipped. 4 | 5 | Default parameters 6 | ################## 7 | cases# 38 8 | sequences flair + X 9 | 10 | max tree-depth 100 11 | sampling# 250k 12 | sampling-strategy startified random 13 | evaluation original space 14 | post-processing <1500 (mm³) 15 | sub-sampling 3³ 16 | pre-processing inter-sequence registration 17 | skull-strip 18 | bias-filed removal 19 | intensity standardization 20 | features LH (11,10), LH (11,20), LH (11,30) 21 | 2D CD in all 3 dimensions 22 | LMG (3), LMG (5), LMG (7) 23 | Intensity 24 | [GGM (5), Median (7)] 25 | 26 | Experiments 27 | ########### 28 | Imp. Type 29 | + A) All possible feature combinations 30 | + B) All possible pre-processing combinations 31 | - C) Different parameters of post-processing step 32 | + D) Different RDF parameters 33 | + E) Different training set sizes 34 | - F) Different training set sampling strategies 35 | + G) Variance of repeated training set sampling 36 | + H) Different sub-sampling 37 | ++ I) All possible sequence combinations 38 | + J) Analysis of (final) trained forest for feature and sequence importances 39 | + K) Satistical influence of lesion and image attributes on the segmentation outcome 40 | 41 | -------------------------------------------------------------------------------- /documentation/stdspace: -------------------------------------------------------------------------------- 1 | #### 2 | # Steps to register the Image to STD space 3 | #### 4 | 5 | 1. Convert all original images from 00original to .nii (as SPM can not read .nii.gz and performs better with skull present) 6 | 2. Create inverse of all t2space preliminary lesion masks (required by SPM) 7 | 3. Run SPM Normalize Estimate 8 | - input is the original T2 image 9 | - mask is the inversed lesion mask 10 | - template is the shipped ICBM T2 template 11 | - smoothing parameter for image is 8 12 | - smoothing parameter for template is 0 13 | => this creates a .mat matlab struct file with the same name (_sn.mat) as the original image and in the same place 14 | 4. Check log output of previous step, and give warning if FHWM value is >= 15 (possibly failed registration, but note that a value < 15 does not ensure a good registration, see case 14) 15 | 5. Create matlab .m scripts for each remaining sequence, with the following functionality 16 | - load and assemple the rigid transformation matrix from the elastic tranformation file 17 | - load the produced T2 _sn.mat struct 18 | - multiply the Affine transformation matric from that file with the rigid one produced before (affine * rigid - matrix multiplication) 19 | - saves the now modified struct as a _sn.mat file for the current sequence 20 | 6. Run the such produced matlab scripts 21 | 7. Run SPM Normalize Write / Warping for each sequence (including T2) to produce the respective image transformed to stdspace with a spacing of 1x1x1 22 | 23 | 24 | -------------------------------------------------------------------------------- /logs/exp00.k.log: -------------------------------------------------------------------------------- 1 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 2 | 03 0.765 31.464 4.545 0.958 0.636 3 | 04 0.713 16.472 2.558 0.709 0.717 4 | 05 0.600 23.622 7.485 0.996 0.429 5 | 06 0.705 25.250 3.467 0.942 0.563 6 | 07 0.884 12.369 1.797 0.943 0.832 7 | 08 0.688 26.906 6.040 0.945 0.541 8 | 09 0.683 10.817 2.225 0.795 0.598 9 | 10 0.535 29.547 6.783 0.976 0.369 10 | 11 0.602 29.547 4.106 0.936 0.443 11 | 12 0.769 24.920 3.492 0.967 0.638 12 | 13 0.853 22.650 2.471 0.872 0.835 13 | 15 0.818 11.225 2.116 0.757 0.891 14 | 17 0.654 57.940 6.689 0.920 0.507 15 | 18 0.851 9.487 1.800 0.843 0.860 16 | 19 0.604 18.972 3.089 0.611 0.597 17 | 20 0.736 116.998 17.250 0.701 0.773 18 | 21 0.827 17.759 1.528 0.927 0.747 19 | 22 0.367 34.598 7.289 0.263 0.607 20 | 23 0.708 15.000 2.334 0.684 0.734 21 | 25 0.625 31.177 4.415 0.622 0.627 22 | 26 0.576 17.748 4.492 0.421 0.912 23 | 28 0.784 24.482 2.453 0.782 0.787 24 | 29 0.607 42.197 4.552 0.759 0.506 25 | 30 0.595 18.899 4.883 0.927 0.438 26 | 31 0.628 21.542 2.615 0.795 0.519 27 | 32 0.701 21.637 2.719 0.709 0.692 28 | 33 0.733 22.122 2.901 0.684 0.789 29 | 34 0.719 35.148 3.633 0.696 0.745 30 | 35 0.764 16.500 3.079 0.961 0.634 31 | 36 0.839 13.544 1.543 0.787 0.899 32 | 37 0.000 67.437 47.941 0.000 0.000 33 | 39 0.525 17.456 2.583 0.657 0.438 34 | 40 0.250 54.246 11.347 0.991 0.143 35 | 41 0.117 43.359 11.745 0.988 0.062 36 | 42 0.607 23.923 2.714 0.881 0.462 37 | 43 0.814 12.864 2.155 0.909 0.737 38 | 44 0.099 28.546 5.346 1.000 0.052 39 | 45 0.518 19.038 3.769 0.713 0.407 40 | -------------------------------------------------------------------------------- /pop_sequencelesionsegmentation.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ##### 4 | # APplyies the forests to a (preliminary) segmentation of the brain lesion in sequence space. 5 | ##### 6 | 7 | ## Changelog 8 | # 2014-05-08 Adapted to the new, distributed calculation scheme. 9 | # 2013-04-03 Added a morphological post-processing step (and removed again). 10 | # 2013-03-25 Updated to new, variable version. 11 | # 2013-11-25 Updated to use new script to distinguish between sequence space and std space features 12 | # 2013-11-05 adapted to new brain mask location 13 | # 2013-10-29 created 14 | 15 | # include shared information 16 | source $(dirname $0)/include.sh 17 | 18 | # main code 19 | log 2 "Applying random decision forests to segment lesion" "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 20 | for i in "${images[@]}"; do 21 | mkdircond ${sequencelesionsegmentation}/${i} 22 | runcond "${scripts}/apply_rdf.py ${sequenceforests}/${i}.pkl ${sequencefeatures}/${i}/ ${sequencebrainmasks}/${i}.nii.gz ${featurecnf} ${sequencelesionsegmentation}/${i}/segmentation.nii.gz ${sequencelesionsegmentation}/${i}/probabilities.nii.gz" 23 | done 24 | 25 | log 2 "Morphological post-processing" "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 26 | function post_processing () 27 | { 28 | i=$1 29 | runcond "${scripts}/remove_small_objects.py ${sequencelesionsegmentation}/${i}/segmentation.nii.gz ${sequencelesionsegmentation}/${i}/segmentation_post.nii.gz ${minimallesionsize}" 30 | } 31 | parallelize post_processing ${threadcount} images[@] 32 | 33 | log 2 "Done." "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 34 | 35 | 36 | -------------------------------------------------------------------------------- /00original/IMAGECHARACTERISTICS_RANKED.csv: -------------------------------------------------------------------------------- 1 | Dataset ID;DB;Lesion Type;Lesion Load (ml);Lesion Age (TSS);NIH SS;WMLs;Flair noise;T1 noise;DW noise;Multifocal? 2 | 3;0;0;246.2;14;14;1;2;2;0;0 3 | 4;0;0;37.5;6;0;2;0;0;0;0 4 | 5;0;1;344.2;14;13;0;3;2;0;0 5 | 6;0;1;127.0;15;13;0;0;0;0;0 6 | 7;0;0;171.2;7;2;2;0;0;0;0 7 | 8;0;0;289.3;7;12;0;2;0;0;0 8 | 9;0;0;8.5;5;3;1;0;0;0;0 9 | 10;0;1;338.8;16;12;3;2;2;0;0 10 | 11;0;0;42.5;6;8;1;0;0;0;1 11 | 12;0;0;141.4;7;5;1;1;0;0;0 12 | 13;0;1;120.6;7;5;1;0;0;0;0 13 | 15;0;1;44.3;8;3;1;0;0;0;0 14 | 17;0;1;99.6;9;2;0;0;0;0;1 15 | 18;0;1;45.3;9;3;1;0;0;0;0 16 | 19;0;0;14.1;4;7;1;0;0;0;0 17 | 20;0;0;36.5;4;5;2;0;0;0;0 18 | 21;0;0;89.5;7;3;1;0;0;0;0 19 | 23;0;0;28.0;6;3;1;0;0;0;1 20 | 25;0;0;18.3;3;7;1;2;2;0;1 21 | 26;0;0;40.6;13;11;1;0;0;0;1 22 | 28;0;0;112.6;7;12;0;2;0;0;0 23 | 29;0;1;49.3;11;12;1;0;0;0;1 24 | 30;1;0;233.4;22;10;1;2;0;0;0 25 | 31;1;1;42.8;8;7;0;0;0;0;1 26 | 32;1;0;58.7;1;14;3;2;2;0;0 27 | 33;1;0;61.8;10;1;0;0;0;0;1 28 | 34;1;0;21.4;6;2;3;0;0;0;0 29 | 35;1;1;124.3;6;12;2;0;2;0;0 30 | 36;1;0;72.1;4;12;0;0;0;0;0 31 | 37;1;0;1.8;;;3;0;0;0;0 32 | 39;1;0;8.6;10;14;3;0;2;0;0 33 | 40;1;1;273.7;8;16;0;0;0;0;1 34 | 41;1;0;117.8;17;2;3;2;0;0;0 35 | 42;1;0;30.3;8;1;1;2;0;0;0 36 | 43;1;0;95.2;5;5;1;3;0;0;0 37 | 44;1;0;6.0;7;3;1;2;0;0;1 38 | 45;1;0;26.0;8;3;3;2;2;0;0 39 | #;;;;;;;;;; 40 | #;0=HEPOKS;0=Ischemic;;;;0=none;0=none;0=none;0=none;0=connected 41 | #;1=JGABLENTZ;1=Ischemic + Haemorrhage;;;;1=small;1=light;1=light;1=light;1=multifocal 42 | #;;;;;;2=medium;2=medium;2=medium;2=medium; 43 | #;;;;;;3=big;3=severe;3=severe;3=severe; 44 | -------------------------------------------------------------------------------- /evaluate_original.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #### 4 | # Evaluate a segmentation in the original space instead of the sequences space. 5 | #### 6 | 7 | # include shared information 8 | source $(dirname $0)/include.sh 9 | 10 | # main code 11 | tmpdir=`mktemp -d` 12 | 13 | function revert() 14 | { 15 | idx=$1 16 | vs=( $(voxelspacing "${segmentations}/${idx}.${imgfiletype}") ) 17 | vs2=$(joinarr " " ${vs[@]}) 18 | runcond "imiImageResample -I ${sequencelesionsegmentation}/${idx}/segmentation_post.${imgfiletype} -O ${tmpdir}/s${idx}.${imgfiletype} -R ${segmentations}/${idx}.${imgfiletype} -s ${vs2} -b" /dev/null 19 | runcond "imiImageResample -I ${sequencebrainmasks}/${idx}.${imgfiletype} -O ${tmpdir}/m${idx}.${imgfiletype} -R ${segmentations}/${idx}.${imgfiletype} -s ${vs2} -b" /dev/null 20 | } 21 | 22 | # revert segmentation to original space for evaluation 23 | log 2 "Reverting segmentations...." "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 24 | parallelize revert ${threadcount} images[@] 25 | 26 | log 2 "Evaluating in original space..." "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 27 | runcond "${scripts}/evaluate_segmentations.py ${tmpdir}/s{}.${imgfiletype} ${segmentations}/{}.${imgfiletype} ${tmpdir}/m{}.${imgfiletype} $(joinarr " " ${images[@]})" 28 | 29 | log 2 "Evaluating in sequence space.." "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 30 | runcond "${scripts}/evaluate_segmentations.py ${sequencelesionsegmentation}/{}/segmentation_post.${imgfiletype} ${sequencesegmentations}/{}.${imgfiletype} ${sequencebrainmasks}/{}.${imgfiletype} $(joinarr " " ${images[@]})" 31 | 32 | emptydircond ${tmpdir} 33 | rmdircond "${tmpdir}" 34 | -------------------------------------------------------------------------------- /scripts/info.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # Scans all image folders and creates a table with detailed information about each image. 4 | 5 | import os 6 | import sys 7 | from medpy.io import load, save, header 8 | 9 | DEBUG = True 10 | FILE_ENDING = 'nii.gz' 11 | 12 | def main(): 13 | srcdir = sys.argv[1] # the image folder contianing the case folders (e.g. data/) 14 | target = sys.argv[2] # the target file where to save the table (in csv format) 15 | 16 | if DEBUG: print 'INFO: Processing all cases in folder {} and saving table as {}.'.format(srcdir, target) 17 | 18 | # check if output file already exists 19 | if os.path.isfile(target): 20 | print 'ERROR: Target file {} already exists. Breaking.'.format(target) 21 | sys.exit(-1) 22 | 23 | # open output file and prepare table header 24 | with open(target, 'w') as f: 25 | f.write('case;image-type;X;Y;Z;Xres;Yres;Zres;data-type;mean;min;max\n') 26 | 27 | # iterate over all cases and add an according line to the table 28 | for root, dirs, files in os.walk(srcdir): 29 | for case in sorted(dirs): 30 | if DEBUG: print 'INFO: Processing case {}.'.format(case) 31 | for root, dirs, files in os.walk('{}/{}'.format(srcdir, case)): 32 | for file_ in files: 33 | if file_.endswith(FILE_ENDING): 34 | imgtype = file_[:-(len(FILE_ENDING) + 1)] 35 | i, h = load('{}/{}/{}'.format(srcdir, case, file_)) 36 | f.write('{};{};{};{};{};{};{};{}\n'.format(case, imgtype, ';'.join(map(str, i.shape)), ';'.join(map(str, header.get_pixel_spacing(h))), i.dtype, i.mean(), i.min(), i.max())) 37 | 38 | print 'Terminated.' 39 | 40 | if __name__ == "__main__": 41 | main() 42 | -------------------------------------------------------------------------------- /scripts/align.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | """ 4 | Aligns the first input image to the second taking origin into account and assuming the same voxel spacing. 5 | Note: This might require the image to be truncated. 6 | arg1: the image to align 7 | arg2: the reference image 8 | arg3: the target output image 9 | """ 10 | 11 | import sys 12 | import numpy 13 | 14 | from medpy.io import load, save, header 15 | 16 | def main(): 17 | i1, h1 = load(sys.argv[1]) 18 | i2, h2 = load(sys.argv[2]) 19 | 20 | # shift image to align origins 21 | origin_h1 = numpy.sign(h1.get_qform()[0:3,0:3]).dot(header.get_offset(h1)) 22 | origin_h2 = numpy.sign(h2.get_qform()[0:3,0:3]).dot(header.get_offset(h2)) 23 | origin_difference_pixel = (origin_h1 - origin_h2) / numpy.asarray(header.get_pixel_spacing(h1)) 24 | # negative values: shift image 1 by this upon inserting (which is the smae as cutting the output image) 25 | # positive values: cut image 1 by this at inserting and also cut right side by length of output image plus this value 26 | o = numpy.zeros(i2.shape, i2.dtype) 27 | o_slicer = [] 28 | i_slicer = [] 29 | for j, p in enumerate(origin_difference_pixel): 30 | if p >= 0: 31 | i_slicer.append(slice(0, min(i1.shape[j], o.shape[j] - abs(p)))) 32 | o_slicer.append(slice(abs(p), min(i1.shape[j] + abs(p), o.shape[j]))) 33 | else: 34 | i_slicer.append(slice(abs(p), min(i1.shape[j], o.shape[j] + abs(p)))) 35 | o_slicer.append(slice(0, min(i1.shape[j] - abs(p), o.shape[j]))) 36 | 37 | o[o_slicer] = i1[i_slicer] 38 | header.set_offset(h1, header.get_offset(h2)) 39 | 40 | save(o, sys.argv[3], h1) 41 | 42 | if __name__ == "__main__": 43 | main() 44 | -------------------------------------------------------------------------------- /logs/eval.rdf.all.log: -------------------------------------------------------------------------------- 1 | INFO: Reverting segmentations.... 2 | INFO: Evaluating in original space... 3 | Metrics: 4 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 5 | 03 0.760 31.931 4.374 0.972 0.624 6 | 05 0.568 23.034 8.057 0.999 0.397 7 | 07 0.846 15.664 1.746 0.963 0.755 8 | 09 0.545 13.280 2.181 0.795 0.414 9 | 10 0.479 28.810 7.415 0.944 0.320 10 | 11 0.487 29.587 4.522 0.817 0.347 11 | 12 0.666 26.041 4.613 0.913 0.524 12 | 13 0.814 21.863 2.333 0.871 0.764 13 | 15 0.745 17.782 2.135 0.707 0.788 14 | DM average 0.656539053223 +/- 0.133458493783 (Median: 0.665709806796) 15 | HD average 23.110112292 +/- 6.17220525772 (Median: 23.0336879646) 16 | ASSD average 4.15288771214 +/- 2.19445793124 (Median: 4.3737431362) 17 | Prec. average 0.886581533681 +/- 0.0916358257111 (Median: 0.912525988251) 18 | Rec. average 0.548080756237 +/- 0.178348484532 (Median: 0.523984648543) 19 | INFO: Evaluating in sequence space.. 20 | Metrics: 21 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 22 | 03 0.768 33.136 4.504 0.963 0.639 23 | 05 0.581 24.187 7.813 0.996 0.411 24 | 07 0.870 15.297 1.979 0.960 0.795 25 | 09 0.600 11.225 2.592 0.813 0.476 26 | 10 0.503 27.000 7.228 0.976 0.339 27 | 11 0.539 29.698 4.659 0.889 0.386 28 | 12 0.718 25.807 4.164 0.976 0.568 29 | 13 0.844 23.431 2.580 0.876 0.815 30 | 15 0.814 11.225 2.176 0.758 0.880 31 | DM average 0.693227016817 +/- 0.131685609312 (Median: 0.718453865337) 32 | HD average 22.3340076441 +/- 7.4961391766 (Median: 24.1867732449) 33 | ASSD average 4.18821780954 +/- 2.02112629691 (Median: 4.16448404939) 34 | Prec. average 0.912045380975 +/- 0.0785194965171 (Median: 0.960248945995) 35 | Rec. average 0.589819571264 +/- 0.191159489112 (Median: 0.568356677846) 36 | 37 | -------------------------------------------------------------------------------- /scripts/make_spm_normalize_write.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | #### 4 | # Creates a Matlab script to warp the different MRI sequences to std-space. 5 | # The method used is: SPM Normalize Write 6 | # arg1: the target matlab script to create 7 | # arg2: the SPM transformation struct containing the desired transformation 8 | # arg3+: the image to transform 9 | #### 10 | 11 | import sys 12 | 13 | def main(): 14 | target = sys.argv[1] 15 | spmstruct = sys.argv[2] 16 | 17 | combined_images = ' '.join(["'{},1'".format(img) for img in sys.argv[3:]]) 18 | script = script_template.format(combined_images, spmstruct, spmstruct, combined_images) 19 | 20 | with open(target, 'w') as f: 21 | f.write(script) 22 | 23 | script_template = """ 24 | % Script to warp the images {} to std-space using {}. 25 | 26 | addpath '/home/maier/Applications/spm8' 27 | 28 | matlabbatch{{1}}.spm.spatial.normalise.write.subj(1).matname = {{'{}'}}; 29 | matlabbatch{{1}}.spm.spatial.normalise.write.subj(1).resample = {{{}}}; 30 | 31 | matlabbatch{{1}}.spm.spatial.normalise.write.roptions.preserve = 0; 32 | matlabbatch{{1}}.spm.spatial.normalise.write.roptions.bb = [-78 -112 -50 33 | 78 76 85]; 34 | matlabbatch{{1}}.spm.spatial.normalise.write.roptions.vox = [1 1 1]; 35 | matlabbatch{{1}}.spm.spatial.normalise.write.roptions.interp = 7; 36 | matlabbatch{{1}}.spm.spatial.normalise.write.roptions.wrap = [0 0 0]; 37 | matlabbatch{{1}}.spm.spatial.normalise.write.roptions.prefix = 'w'; 38 | 39 | spm('defaults', 'FMRI'); 40 | spm_jobman('initcfg'); 41 | spm_jobman('serial', matlabbatch); 42 | 43 | exit; 44 | """ 45 | 46 | if __name__ == "__main__": 47 | main() 48 | -------------------------------------------------------------------------------- /metadata.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | """ 4 | Prints out handy information about the metadata of an NifTi image, especially regarding the transformation to world coordinates. 5 | arg1: the image to check 6 | """ 7 | 8 | import sys 9 | 10 | import numpy 11 | 12 | from medpy.io import load, header 13 | 14 | def main(): 15 | i, h = load(sys.argv[1]) 16 | 17 | print 'Image:\t{}'.format(sys.argv[1]) 18 | print 'Shape:\t{}'.format(i.shape) 19 | print 'Spacing:{}'.format(header.get_pixel_spacing(h)) 20 | print 'Offset:\t{}'.format(header.get_offset(h)) 21 | 22 | if 0 == h.get_header()['qform_code']: 23 | method = 'ANALYZE 7.5 (old)' 24 | if h.get_header()['qform_code'] > 0: 25 | method = 'Normal (qform)' 26 | if h.get_header()['sform_code'] > 0: 27 | method = 'Special space (sform)' 28 | 29 | print 30 | print 'Orientation and location in space:' 31 | print 'Type:\t\t{}'.format(method) 32 | print 'qform_code:\t{}'.format(h.get_header()['qform_code']) 33 | print 'sform_code:\t{}'.format(h.get_header()['sform_code']) 34 | 35 | print 36 | print 'qform == sform?\t{} (max diff={})'.format(numpy.all(h.get_qform() == h.get_sform()), numpy.max(numpy.abs(h.get_qform() - h.get_sform()))) 37 | print 'affine = qform?\t{} (max diff={})'.format(numpy.all(h.get_affine() == h.get_qform()), numpy.max(numpy.abs(h.get_affine() - h.get_qform()))) 38 | print 'affine = sform?\t{} (max diff={})'.format(numpy.all(h.get_affine() == h.get_sform()), numpy.max(numpy.abs(h.get_affine() - h.get_sform()))) 39 | 40 | print 41 | print 'qform:' 42 | print h.get_qform() 43 | print 'sform:' 44 | print h.get_sform() 45 | print 'affine:' 46 | print h.get_affine() 47 | 48 | if __name__ == "__main__": 49 | main() 50 | -------------------------------------------------------------------------------- /scripts/make_spm_normalize_write_mask.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | #### 4 | # Creates a Matlab script to warp the different MRI sequences to std-space. 5 | # This version is for warping binary files with a reduced bspline order. 6 | # The method used is: SPM Normalize Write 7 | # arg1: the target matlab script to create 8 | # arg2: the SPM transformation struct containing the desired transformation 9 | # arg3+: the image to transform 10 | #### 11 | 12 | import sys 13 | 14 | def main(): 15 | target = sys.argv[1] 16 | spmstruct = sys.argv[2] 17 | 18 | combined_images = ' '.join(["'{},1'".format(img) for img in sys.argv[3:]]) 19 | script = script_template.format(combined_images, spmstruct, spmstruct, combined_images) 20 | 21 | with open(target, 'w') as f: 22 | f.write(script) 23 | 24 | script_template = """ 25 | % Script to warp the images {} to std-space using {}. 26 | 27 | addpath '/home/maier/Applications/spm8' 28 | 29 | matlabbatch{{1}}.spm.spatial.normalise.write.subj(1).matname = {{'{}'}}; 30 | matlabbatch{{1}}.spm.spatial.normalise.write.subj(1).resample = {{{}}}; 31 | 32 | matlabbatch{{1}}.spm.spatial.normalise.write.roptions.preserve = 0; 33 | matlabbatch{{1}}.spm.spatial.normalise.write.roptions.bb = [-78 -112 -50 34 | 78 76 85]; 35 | matlabbatch{{1}}.spm.spatial.normalise.write.roptions.vox = [1 1 1]; 36 | matlabbatch{{1}}.spm.spatial.normalise.write.roptions.interp = 0; 37 | matlabbatch{{1}}.spm.spatial.normalise.write.roptions.wrap = [0 0 0]; 38 | matlabbatch{{1}}.spm.spatial.normalise.write.roptions.prefix = 'w'; 39 | 40 | spm('defaults', 'FMRI'); 41 | spm_jobman('initcfg'); 42 | spm_jobman('serial', matlabbatch); 43 | 44 | exit; 45 | """ 46 | 47 | if __name__ == "__main__": 48 | main() 49 | -------------------------------------------------------------------------------- /scripts/morphology.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | """ 4 | Applies a post-processing morphological step to binary images. 5 | Note: Takes voxel-spacing into account. 6 | Note: Does not remove small objects if the binary mask would be empty afterwards. 7 | .py 8 | """ 9 | 10 | import sys 11 | import numpy 12 | from medpy.io import load, save, header 13 | from scipy.ndimage.morphology import binary_opening, binary_closing,\ 14 | binary_erosion, binary_dilation, binary_fill_holes 15 | 16 | def main(): 17 | i, h = load(sys.argv[1]) 18 | ibo, ibc, ibe, ibd = map(int, sys.argv[3:]) 19 | 20 | i = binary_fill_holes(i) 21 | 22 | if not 0 == ibo: i = binary_opening(i, structure=None, iterations=ibo) 23 | if not 0 == ibc: i = binary_closing(i, structure=None, iterations=ibc) 24 | 25 | if not 0 == ibe: i = binary_erosion(i, structure=None, iterations=ibe) 26 | if not 0 == ibd: i = binary_dilation(i, structure=None, iterations=ibd) 27 | 28 | #i = morphology2d(binary_opening, i, structure=1, iterations=1) 29 | #i = morphology2d(binary_closing, i, structure=1, iterations=1) 30 | 31 | #i = morphology2d(binary_erosion, i, structure=1, iterations=1) 32 | #i = morphology2d(binary_dilation, i, structure=1, iterations=1) 33 | 34 | if 0 == numpy.count_nonzero(i): 35 | raise Warning("{}: empty segmentation resulted".format(sys.argv[1])) 36 | 37 | save(i, sys.argv[2], h, True) 38 | 39 | def morphology2d(operation, arr, structure = None, iterations=1, dimension = 2): 40 | res = numpy.zeros(arr.shape, numpy.bool) 41 | for sl in range(processed.shape[dimension]): 42 | res[:,:,sl] = operation(arr[:,:,sl], structure, iterations) 43 | return res 44 | 45 | if __name__ == "__main__": 46 | main() 47 | 48 | 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # workflow files # 2 | ################## 3 | todo.txt 4 | *.csv 5 | 6 | # Local files to exclude # 7 | ########################## 8 | 01t2space/show.sh 9 | 06stdspace/show.sh 10 | 11 | # Pickle Python classes and NumpPy arrays # 12 | ########################################### 13 | *.pkl 14 | *.npy 15 | 16 | # Images # 17 | ########## 18 | *.dcm 19 | *.nii.gz 20 | *.nii 21 | *.mha 22 | *.mhd 23 | *.raw 24 | 25 | # Only locally used, temporary .py scripts. # 26 | ############################################# 27 | _*.py 28 | !__init__.py 29 | 30 | # Compiled source # 31 | ################### 32 | *.com 33 | *.class 34 | *.dll 35 | *.exe 36 | *.o 37 | *.so 38 | *.pyc 39 | *.pyo 40 | 41 | # Packages # 42 | ############ 43 | # it's better to unpack these files and commit the raw source 44 | # git has its own built in compression methods 45 | *.7z 46 | *.dmg 47 | *.gz 48 | *.iso 49 | *.jar 50 | *.rar 51 | *.tar 52 | *.zip 53 | 54 | # Logs and databases # 55 | ###################### 56 | *.log 57 | *.sql 58 | *.sqlite 59 | 60 | # OS generated files # 61 | ###################### 62 | .DS_Store* 63 | ehthumbs.db 64 | Icon? 65 | Thumbs.db 66 | *~ 67 | 68 | # Eclipse and PyDev project files # 69 | ################################### 70 | .project 71 | .pydevproject 72 | .settings/ 73 | 74 | # Suggestions by GitHub for Python projects # 75 | ############################################# 76 | # Packages 77 | *.egg 78 | *.egg-info 79 | dist 80 | build 81 | eggs 82 | parts 83 | var 84 | sdist 85 | develop-eggs 86 | .installed.cfg 87 | 88 | # Installer logs 89 | pip-log.txt 90 | 91 | # Unit test / coverage reports 92 | .coverage 93 | .tox 94 | 95 | #Translations 96 | *.mo 97 | 98 | #Mr Developer 99 | .mr.developer.cfg 100 | -------------------------------------------------------------------------------- /scripts/equalvs.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # Checks whether the (equally named) images in two folders have the same voxel spacing 4 | # You can additionally supply a "-i" switch at the end to treat the second folder as flat structure (e.g. the ones containing masks or segmentations) 5 | 6 | import os 7 | import sys 8 | import numpy 9 | from medpy.io import load, save, header 10 | 11 | DEBUG = True 12 | FILE_ENDING = 'nii.gz' 13 | 14 | def main(): 15 | onedir = sys.argv[1] # the first folder containing case folders 16 | twodir = sys.argv[2] # the second folder containing case folders 17 | nocase = (len(sys.argv) > 3 and sys.argv[3] == '-i') 18 | 19 | if DEBUG: print 'INFO: Comparing all cases in folders {} and {}.'.format(onedir, twodir) 20 | 21 | # iterate over first folder and compare voxel spacings with equivalent image in second folder 22 | print "Case\tvs same\tshape same" 23 | for root, dirs, files in os.walk(onedir): 24 | for case in sorted(dirs): 25 | for root, dirs, files in os.walk('{}/{}'.format(onedir, case)): 26 | for file_ in files: 27 | if file_.endswith(FILE_ENDING): 28 | i, hi = load('{}/{}/{}'.format(onedir, case, file_)) 29 | if nocase: 30 | j, hj = load('{}/{}.{}'.format(twodir, case, FILE_ENDING)) 31 | else: 32 | j, hj = load('{}/{}/{}'.format(twodir, case, file_)) 33 | vs_same = numpy.array_equal(header.get_pixel_spacing(hi), header.get_pixel_spacing(hj)) 34 | shape_same = numpy.array_equal(i.shape, j.shape) 35 | print '{}\t{}\t{}'.format(case, vs_same, shape_same) 36 | if not vs_same: 37 | print "\t{} vs {}".format(header.get_pixel_spacing(hi), header.get_pixel_spacing(hj)) 38 | if not shape_same: 39 | print "\t{} vs {}".format(i.shape, j.shape) 40 | print 'Terminated.' 41 | 42 | if __name__ == "__main__": 43 | main() 44 | -------------------------------------------------------------------------------- /scripts/make_spm_normalize_estimate.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | #### 4 | # Creates a Matlab script to register a FLAIR image to the std-space FLAIR template using a lesion mask to mask out pathological areas. 5 | # The method used is: SPM Normalize Estimate 6 | # arg1: the FLAIR image to register to std-space 7 | # arg2: the associated lesion mask (note: must contain zeros in places of pathological tissue) 8 | # arg3: the target matlab script file 9 | #### 10 | 11 | import sys 12 | 13 | def main(): 14 | flairfile = sys.argv[1] 15 | lmask = sys.argv[2] 16 | target = sys.argv[3] 17 | 18 | script = script_template.format(flairfile, lmask, flairfile, lmask) 19 | 20 | with open(target, 'w') as f: 21 | f.write(script) 22 | 23 | script_template = """ 24 | % Script to register the image {} to the std-space, taking into account the lesion mask {}. 25 | 26 | addpath '/home/maier/Applications/spm8' 27 | 28 | matlabbatch{{1}}.spm.spatial.normalise.est.subj(1).source = {{'{},1'}}; 29 | matlabbatch{{1}}.spm.spatial.normalise.est.subj(1).wtsrc = {{'{},1'}}; 30 | matlabbatch{{1}}.spm.spatial.normalise.est.eoptions.template = {{'/home/maier/Applications/spm8/templates/GG-366-FLAIR-1.0mm.nii,1'}}; 31 | matlabbatch{{1}}.spm.spatial.normalise.est.eoptions.weight = ''; 32 | matlabbatch{{1}}.spm.spatial.normalise.est.eoptions.smosrc = 8; 33 | matlabbatch{{1}}.spm.spatial.normalise.est.eoptions.smoref = 8; 34 | matlabbatch{{1}}.spm.spatial.normalise.est.eoptions.regtype = 'mni'; 35 | matlabbatch{{1}}.spm.spatial.normalise.est.eoptions.cutoff = 25; 36 | matlabbatch{{1}}.spm.spatial.normalise.est.eoptions.nits = 16; 37 | matlabbatch{{1}}.spm.spatial.normalise.est.eoptions.reg = 1; 38 | 39 | spm('defaults', 'FMRI'); 40 | spm_jobman('initcfg'); 41 | spm_jobman('serial', matlabbatch); 42 | 43 | exit; 44 | """ 45 | 46 | if __name__ == "__main__": 47 | main() 48 | -------------------------------------------------------------------------------- /experiments/05flairlesionsegmentation: -------------------------------------------------------------------------------- 1 | Some remarks: 2 | - Keep in mind, that the goal is actually not to find the lesion, but all white matter hyperintensities! 3 | - Large lesions and WMI should be found, smaller ones are rather irrelevant. 4 | - Skull and meninges should rather not be excluded. 5 | 6 | ! Morphological operations, except hole closing, switched off in apply_rdf.py ! 7 | 8 | 1. FLAIR & intensity only performance 9 | @results: logs/eval.pre.flair.int.log 10 | Visual examination: 11 | Horrible. Lesion is encountered to some extend reliably, but there 12 | are huge amounts of false positives all over the brain matter and 13 | especially in the skull and meninges where missed by the skull strip. 14 | Conclusion: 15 | => Like this not suitable at all for masking out the lesions during registration. 16 | 17 | 2. FLAIR & feature combination performance 18 | @results: logs/eval.pre.flair.int_lmg3_lh1111.log 19 | @results: logs/eval.pre.flair.int_[...] 20 | Visual examination: 21 | A92gKwq4 22 | 23 | Conclusion: 24 | => 25 | 26 | 3. Best sampling size for best feature combo from (2) 27 | @results: logs/eval.pre.sampling.Xk.log 28 | Runtimes: 29 | 30 | Visual examination: 31 | 32 | Conclusion: 33 | => 34 | 35 | 4. Add DW as additional sequence 36 | @results: logs/eval.pre.flair_dw.int_[...].log 37 | Visual examination: 38 | 39 | Conclusion: 40 | => 41 | 42 | 5. Intensity normalization (with best of (1)-(4)) 43 | Strategies: 44 | a) disable 45 | b) intensity normalization (Oskar) 46 | c) intensity normalization (Nils) 47 | e) simple percentile (0.5, 99.5) => [0, 1] 48 | 49 | 6. Enable bias correction on best result 50 | Does it increase the results? 51 | Keep the remarks on top of this file in mind! 52 | 53 | 7. Register to std-brain and check visually the results 54 | Should be good in ALL cases! 55 | 56 | 57 | -------------------------------------------------------------------------------- /logs/exp00.k.log~: -------------------------------------------------------------------------------- 1 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 2 | 03 0.765 31.464 4.545 0.958 0.636 3 | 04 0.713 16.472 2.558 0.709 0.717 4 | 05 0.600 23.622 7.485 0.996 0.429 5 | 06 0.705 25.250 3.467 0.942 0.563 6 | 07 0.884 12.369 1.797 0.943 0.832 7 | 08 0.688 26.906 6.040 0.945 0.541 8 | 09 0.683 10.817 2.225 0.795 0.598 9 | 10 0.535 29.547 6.783 0.976 0.369 10 | 11 0.602 29.547 4.106 0.936 0.443 11 | 12 0.769 24.920 3.492 0.967 0.638 12 | 13 0.853 22.650 2.471 0.872 0.835 13 | 15 0.818 11.225 2.116 0.757 0.891 14 | 17 0.654 57.940 6.689 0.920 0.507 15 | 18 0.851 9.487 1.800 0.843 0.860 16 | 19 0.604 18.972 3.089 0.611 0.597 17 | 20 0.736 116.998 17.250 0.701 0.773 18 | 21 0.827 17.759 1.528 0.927 0.747 19 | 22 0.367 34.598 7.289 0.263 0.607 20 | 23 0.708 15.000 2.334 0.684 0.734 21 | 25 0.625 31.177 4.415 0.622 0.627 22 | 26 0.576 17.748 4.492 0.421 0.912 23 | 28 0.784 24.482 2.453 0.782 0.787 24 | 29 0.607 42.197 4.552 0.759 0.506 25 | 30 0.595 18.899 4.883 0.927 0.438 26 | 31 0.628 21.542 2.615 0.795 0.519 27 | 32 0.701 21.637 2.719 0.709 0.692 28 | 33 0.733 22.122 2.901 0.684 0.789 29 | 34 0.719 35.148 3.633 0.696 0.745 30 | 35 0.764 16.500 3.079 0.961 0.634 31 | 36 0.839 13.544 1.543 0.787 0.899 32 | 37 0.000 67.437 47.941 0.000 0.000 33 | 39 0.525 17.456 2.583 0.657 0.438 34 | 40 0.250 54.246 11.347 0.991 0.143 35 | 41 0.117 43.359 11.745 0.988 0.062 36 | 42 0.607 23.923 2.714 0.881 0.462 37 | 43 0.814 12.864 2.155 0.909 0.737 38 | 44 0.099 28.546 5.346 1.000 0.052 39 | 45 0.518 19.038 3.769 0.713 0.407 40 | DM average 0.685934792405 +/- 0.136963523004 (Median: 0.682568807339) 41 | HD average 24.1406034689 +/- 12.2160248918 (Median: 23.622023622) 42 | ASSD average 4.13580067957 +/- 2.00250723725 (Median: 4.1055353599) 43 | Prec. average 0.796865895485 +/- 0.209966420695 (Median: 0.871619975639) 44 | Rec. average 0.661141575345 +/- 0.17115161993 (Median: 0.636394366197) 45 | -------------------------------------------------------------------------------- /logs/eval.shifted_gauss.log: -------------------------------------------------------------------------------- 1 | INFO: Compute overall evaluation 2 | Metrics: 3 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 4 | 03 0.592 36.000 7.467 0.977 0.425 5 | 04 0.738 64.761 6.149 0.726 0.750 6 | 05 0.356 36.249 11.058 0.999 0.217 7 | 06 0.765 21.000 3.412 0.964 0.635 8 | 07 0.845 13.748 2.341 0.943 0.766 9 | 08 0.672 26.833 5.958 0.981 0.511 10 | 09 0.688 9.950 2.129 0.752 0.633 11 | 10 0.461 31.464 7.841 0.981 0.302 12 | 11 0.487 43.058 6.407 0.972 0.325 13 | 12 0.793 19.672 3.020 0.965 0.673 14 | 13 0.807 24.920 2.987 0.918 0.719 15 | 15 0.783 15.297 2.383 0.820 0.750 16 | 17 0.806 15.588 2.827 0.781 0.833 17 | 18 0.725 15.588 2.808 0.949 0.586 18 | 19 0.546 19.209 4.118 0.580 0.516 19 | 20 0.862 7.348 1.579 0.896 0.831 20 | 21 0.818 17.748 2.407 0.931 0.730 21 | 22 0.234 25.807 8.101 0.188 0.311 22 | 23 0.466 35.623 7.473 0.516 0.425 23 | 25 0.612 23.622 3.709 0.510 0.767 24 | 26 0.689 18.493 3.177 0.558 0.899 25 | 28 0.817 28.302 2.848 0.854 0.783 26 | 29 0.711 42.426 4.223 0.835 0.620 27 | 30 0.506 30.150 6.720 0.930 0.347 28 | 31 0.600 30.299 4.321 0.871 0.458 29 | 32 0.581 62.642 7.474 0.624 0.543 30 | 33 0.515 21.213 4.971 0.980 0.350 31 | 34 0.796 12.728 1.929 0.880 0.728 32 | 35 0.774 15.297 3.321 0.955 0.651 33 | 36 0.857 15.297 1.966 0.849 0.866 34 | 37 0.000 58.249 47.870 0.000 0.000 35 | 39 0.669 9.950 2.133 0.775 0.589 36 | 40 0.297 45.989 9.307 0.974 0.175 37 | 41 0.027 49.020 14.591 1.000 0.014 38 | 42 0.495 52.564 11.498 0.624 0.410 39 | 43 0.698 17.234 4.156 0.949 0.552 40 | 44 0.000 inf inf 0.000 0.000 41 | 45 0.403 20.125 6.370 0.500 0.338 42 | WARNING: Average values only computed on 37 of 38 cases! 43 | DM average 0.607974562343 +/- 0.215249554324 (Median: 0.672243346008) 44 | HD average 27.931500545 +/- 15.1021362909 (Median: 23.622023622) 45 | ASSD average 6.24451314798 +/- 7.56501913869 (Median: 4.1560277852) 46 | Prec. average 0.797458393803 +/- 0.228641431801 (Median: 0.879573170732) 47 | Rec. average 0.541243874661 +/- 0.229250343801 (Median: 0.585995085995) 48 | -------------------------------------------------------------------------------- /scripts/niftimodifymetadata.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | """ 4 | Modifies a NifTi file's metadata in place. 5 | arg1: the image to modify 6 | arg2+: the changes to make in order of appearance 7 | qfc=x : set qform_code = x 8 | sfc=x : set sform_code = x 9 | qfc=sfc : set sform_code = qform_code 10 | sfc=qfc : set sform_code = qform_code 11 | qf=dia : set qform = diag(spacing) 12 | sf=dia : set sform = diag(spacing) 13 | qf=sf : set qform = sform 14 | sf=qf : set sform = qform 15 | qf=aff : set qform = affine 16 | sf=aff : set sform = affine 17 | """ 18 | 19 | import sys 20 | 21 | import numpy 22 | 23 | from medpy.io import load, save, header 24 | 25 | def main(): 26 | i, h = load(sys.argv[1]) 27 | 28 | tasks = sys.argv[2:] 29 | 30 | for task in sys.argv[2:]: 31 | s, g = task.split('=') 32 | if g in GETTER: 33 | SETTER[s](h, GETTER[g](h)) 34 | else: 35 | SETTER[s](h, int(g)) 36 | 37 | save(i.copy(), sys.argv[1], h) 38 | 39 | def __set_qform_code(h, v): 40 | h.get_header()['qform_code'] = v 41 | 42 | def __set_sform_code(h, v): 43 | h.get_header()['sform_code'] = v 44 | 45 | def __set_qform(h, v): 46 | h.set_qform(v) 47 | 48 | def __set_sform(h, v): 49 | h.set_sform(v) 50 | 51 | def __get_qform_code(h): 52 | return h.get_header()['qform_code'] 53 | 54 | def __get_sform_code(h): 55 | return h.get_header()['sform_code'] 56 | 57 | def __get_affine(h): 58 | return h.get_affine() 59 | 60 | def __get_qform(h): 61 | return h.get_qform() 62 | 63 | def __get_sform(h): 64 | return h.get_sform() 65 | 66 | def __get_diagonal(h): 67 | return numpy.diag(list(header.get_pixel_spacing(h)) + [1]) 68 | 69 | SETTER = { 70 | 'qfc' : __set_qform_code, 71 | 'sfc' : __set_sform_code, 72 | 'qf' : __set_qform, 73 | 'sf' : __set_sform} 74 | GETTER = { 75 | 'qfc' : __get_qform_code, 76 | 'sfc' : __get_sform_code, 77 | 'aff' : __get_affine, 78 | 'qf' : __get_qform, 79 | 'sf' : __get_sform, 80 | 'dia' : __get_diagonal} 81 | 82 | if __name__ == "__main__": 83 | main() 84 | -------------------------------------------------------------------------------- /00original/GROUPINGS: -------------------------------------------------------------------------------- 1 | BASE SET: 2 | 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15, 17, 18, 19, 20, 21, 22, 23, 25, 26, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 40, 41, 42, 43, 44, 45 3 | (has FLAIR & mostly ischemic & is ground truth) 4 | 5 | T2 SET: 6 | (BASE SET & suitable T2 sequence) 7 | => Influence of T2 sequence 8 | 9 | DW SET: 10 | (BASE SET & DW1000 mean sequence present) 11 | => Influence of DW sequence (especially in conjunction with DISTRACTION SET) 12 | 13 | FLIPPED SET: 14 | (BASET SET \w half of the lesions flipped) 15 | => Influence of lesion hemisphere on results) 16 | 17 | CONNECTED SET: 18 | (BASE SET & ground truth completely connected in 3D) 19 | => Allows to enable largest connected component preprocessing 20 | 21 | GOOD GROUND TRUTH SET: 22 | (BASE SET & no negative ground truth remarks) 23 | => Influence of ground truth quality on results 24 | 25 | GOOD SCAN SET: 26 | (BASE SET & no imaging artifacts) 27 | => Influence of image quality on results 28 | 29 | DISTRACTION SET: 30 | (BASE SET & lesion similar hyperintensities (LSH) >= middle) 31 | => Influence of LSH occurences 32 | 33 | ISCHEMIC SET: 34 | (BASE SET & has ischemic stroke only) 35 | => Influence of hemorrhage ocurrence on results 36 | 37 | HEMORRHAGIC SET: 38 | (BASE SET & has hemorrhage) 39 | => Influence of hemorrhage ocurrence on results 40 | 41 | HEOPKS SET: 42 | (BASE SET & HEOPKS database) 43 | => Compare single vs. two sets 44 | 45 | JGABLENTZ SET: 46 | (BASE SET & JGABLENTZ database) 47 | => Compare single vs. two sets 48 | 49 | LESION LOAD SETS: 50 | (BASE SET & a) lesion size > median size resp. b) lesion size <= median size) 51 | => Check inlfuence of lesion size dedicated detectors 52 | 53 | LESION AGE SETS: 54 | (BASE SET & a) lesion age > median age resp b) lesion age <= median age) 55 | => Check quality of lesion age dedicated detectors 56 | 57 | NIHSS SETS: 58 | (BASE SET & a) nihss score > median score resp. b) nihss score <= median score) 59 | => Check inlfuence of stroke serverity on results 60 | 61 | -------------------------------------------------------------------------------- /scripts/train_rdf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | """ 4 | Train a decision forest on a training set. 5 | arg1: the training set file (.features.npy) 6 | arg2: the decision forest target file 7 | arg4: the maximum tree depth (optional) 8 | """ 9 | 10 | import sys 11 | import pickle 12 | import numpy 13 | 14 | from sklearn.ensemble.forest import ExtraTreesClassifier 15 | from sklearn.ensemble.forest import RandomForestClassifier 16 | #from sklearn.ensemble.forest import MixedForestClassifier 17 | 18 | # constants 19 | n_jobs = 6 20 | 21 | def main(): 22 | # catch parameters 23 | training_set_features = sys.argv[1] 24 | training_set_classes = training_set_features.replace('features', 'classes') 25 | forest_file = sys.argv[2] 26 | max_depth = int(sys.argv[3]) if 3 <= len(sys.argv) else 500 27 | 28 | # loading training features 29 | with open(training_set_features, 'r') as f: 30 | training_feature_vector = numpy.load(f) 31 | if 1 == training_feature_vector.ndim: 32 | training_feature_vector = numpy.expand_dims(training_feature_vector, -1) 33 | with open(training_set_classes , 'r') as f: 34 | training_class_vector = numpy.load(f) 35 | 36 | # prepare and train the decision forest 37 | forest = RandomForestClassifier(n_estimators=200, 38 | criterion = 'entropy', 39 | max_features = 'auto', # rdf: auto / et: None 40 | #splitter="alternatingnode", 41 | min_samples_split = 2, 42 | min_samples_leaf = 1, 43 | max_depth = max_depth, 44 | bootstrap = True, 45 | oob_score = False, 46 | random_state=None, 47 | n_jobs=n_jobs, 48 | compute_importances=True) 49 | forest.fit(training_feature_vector, training_class_vector) 50 | 51 | # saving the decision forest 52 | with open(forest_file, 'wb') as f: 53 | pickle.dump(forest, f) 54 | 55 | if __name__ == "__main__": 56 | main() 57 | -------------------------------------------------------------------------------- /logs/exp00.g.log: -------------------------------------------------------------------------------- 1 | INFO: Reverting segmentations.... 2 | INFO: Evaluating in original space... 3 | Metrics: 4 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 5 | 03 0.759 30.848 4.353 0.968 0.625 6 | 05 0.587 23.125 7.777 0.999 0.415 7 | 07 0.859 11.283 1.536 0.941 0.791 8 | 09 0.611 11.557 1.607 0.741 0.520 9 | 10 0.509 28.695 7.066 0.941 0.349 10 | 11 0.558 28.361 3.841 0.882 0.408 11 | 12 0.707 25.615 4.116 0.903 0.581 12 | 13 0.828 21.613 2.157 0.871 0.790 13 | 15 0.744 17.782 2.048 0.700 0.793 14 | 17 0.648 55.862 5.484 0.923 0.500 15 | 18 0.843 11.405 1.161 0.853 0.833 16 | 22 0.288 37.650 7.885 0.207 0.471 17 | 23 0.710 15.118 1.884 0.707 0.714 18 | 25 0.635 34.955 3.561 0.646 0.624 19 | 26 0.531 18.925 3.740 0.395 0.809 20 | DM average 0.654518839481 +/- 0.145990876646 (Median: 0.648496715969) 21 | HD average 24.8531356843 +/- 11.622048977 (Median: 23.1254952043) 22 | ASSD average 3.8810812059 +/- 2.20155035686 (Median: 3.73973780529) 23 | Prec. average 0.778441824632 +/- 0.21629558591 (Median: 0.870786687913) 24 | Rec. average 0.614855006777 +/- 0.160428391174 (Median: 0.623921234958) 25 | INFO: Evaluating in sequence space.. 26 | Metrics: 27 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 28 | 03 0.765 31.464 4.545 0.958 0.636 29 | 05 0.600 23.622 7.485 0.996 0.429 30 | 07 0.884 12.369 1.797 0.943 0.832 31 | 09 0.683 10.817 2.225 0.795 0.598 32 | 10 0.535 29.547 6.783 0.976 0.369 33 | 11 0.602 29.547 4.106 0.936 0.443 34 | 12 0.769 24.920 3.492 0.967 0.638 35 | 13 0.853 22.650 2.471 0.872 0.835 36 | 15 0.818 11.225 2.116 0.757 0.891 37 | 17 0.654 57.940 6.689 0.920 0.507 38 | 18 0.851 9.487 1.800 0.843 0.860 39 | 22 0.367 34.598 7.289 0.263 0.607 40 | 23 0.708 15.000 2.334 0.684 0.734 41 | 25 0.625 31.177 4.415 0.622 0.627 42 | 26 0.576 17.748 4.492 0.421 0.912 43 | DM average 0.685934792405 +/- 0.136963523004 (Median: 0.682568807339) 44 | HD average 24.1406034689 +/- 12.2160248918 (Median: 23.622023622) 45 | ASSD average 4.13580067957 +/- 2.00250723725 (Median: 4.1055353599) 46 | Prec. average 0.796865895485 +/- 0.209966420695 (Median: 0.871619975639) 47 | Rec. average 0.661141575345 +/- 0.17115161993 (Median: 0.636394366197) 48 | -------------------------------------------------------------------------------- /logs/exp00.h.log: -------------------------------------------------------------------------------- 1 | INFO: Reverting segmentations.... 2 | INFO: Evaluating in original space... 3 | Metrics: 4 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 5 | 03 0.746 31.931 4.569 0.968 0.607 6 | 05 0.569 24.033 7.882 0.998 0.398 7 | 07 0.851 12.258 1.694 0.942 0.777 8 | 09 0.592 12.087 1.711 0.758 0.485 9 | 10 0.498 29.225 7.216 0.934 0.339 10 | 11 0.569 28.361 3.891 0.891 0.418 11 | 12 0.726 24.648 3.810 0.880 0.618 12 | 13 0.823 21.863 2.211 0.867 0.783 13 | 15 0.737 17.782 2.221 0.709 0.768 14 | 17 0.627 58.053 5.845 0.921 0.475 15 | 18 0.842 11.476 1.127 0.874 0.812 16 | 22 0.315 37.992 7.688 0.227 0.514 17 | 23 0.719 15.118 1.811 0.698 0.741 18 | 25 0.670 27.713 2.199 0.631 0.713 19 | 26 0.547 18.797 3.543 0.419 0.788 20 | DM average 0.655364947753 +/- 0.140946271741 (Median: 0.669787622745) 21 | HD average 24.7557832957 +/- 11.7077151118 (Median: 24.0326776564) 22 | ASSD average 3.82802052848 +/- 2.24750602205 (Median: 3.5433935284) 23 | Prec. average 0.781166235167 +/- 0.210094193646 (Median: 0.874123477619) 24 | Rec. average 0.615777395985 +/- 0.159360828314 (Median: 0.618176573805) 25 | INFO: Evaluating in sequence space.. 26 | Metrics: 27 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 28 | 03 0.752 33.136 4.768 0.958 0.619 29 | 05 0.582 25.632 7.759 0.996 0.411 30 | 07 0.880 13.748 1.834 0.946 0.823 31 | 09 0.655 10.817 2.356 0.797 0.556 32 | 10 0.526 31.321 7.034 0.971 0.361 33 | 11 0.599 29.547 4.163 0.923 0.443 34 | 12 0.793 24.556 3.199 0.944 0.684 35 | 13 0.844 23.431 2.568 0.866 0.824 36 | 15 0.815 11.225 2.117 0.769 0.866 37 | 17 0.640 59.548 6.825 0.927 0.489 38 | 18 0.852 12.369 1.784 0.865 0.840 39 | 22 0.404 35.623 6.884 0.291 0.663 40 | 23 0.712 15.000 2.336 0.675 0.753 41 | 25 0.671 22.450 3.027 0.615 0.737 42 | 26 0.598 17.493 4.209 0.450 0.893 43 | DM average 0.688299563125 +/- 0.131075957305 (Median: 0.670790378007) 44 | HD average 24.3930127001 +/- 12.3036958436 (Median: 23.4307490277) 45 | ASSD average 4.05759036201 +/- 2.04130636015 (Median: 3.19900989749) 46 | Prec. average 0.799570579643 +/- 0.201187074805 (Median: 0.866077998528) 47 | Rec. average 0.664154753517 +/- 0.170862107691 (Median: 0.683764056027) 48 | -------------------------------------------------------------------------------- /logs/eval.condnodes.0.05.log: -------------------------------------------------------------------------------- 1 | INFO: Reverting segmentations.... 2 | INFO: Evaluating in original space... 3 | Metrics: 4 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 5 | 03 0.798 30.848 3.467 0.948 0.689 6 | 05 0.610 22.340 7.193 0.998 0.439 7 | 07 0.857 11.311 1.606 0.930 0.794 8 | 09 0.255 17.123 3.717 0.606 0.161 9 | 10 0.510 30.887 7.238 0.939 0.350 10 | 11 0.449 25.926 4.418 0.725 0.326 11 | 12 0.716 23.039 3.694 0.881 0.603 12 | 13 0.790 21.302 2.658 0.862 0.729 13 | 15 0.716 17.782 2.209 0.685 0.749 14 | 17 0.519 63.289 6.533 0.824 0.379 15 | 18 0.832 19.006 1.284 0.843 0.822 16 | 22 0.309 39.392 7.518 0.226 0.490 17 | 23 0.688 17.763 1.835 0.693 0.684 18 | 25 0.622 32.841 3.792 0.595 0.653 19 | 26 0.480 20.340 4.135 0.338 0.828 20 | DM average 0.610133489649 +/- 0.179698389735 (Median: 0.622393419833) 21 | HD average 26.2126594523 +/- 12.1612872216 (Median: 22.3398830242) 22 | ASSD average 4.08641551168 +/- 2.04725304767 (Median: 3.71677195636) 23 | Prec. average 0.739542421638 +/- 0.217298204186 (Median: 0.824421369305) 24 | Rec. average 0.579739452723 +/- 0.201163392919 (Median: 0.653032697216) 25 | INFO: Evaluating in sequence space.. 26 | Metrics: 27 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 28 | 03 0.808 31.177 3.725 0.940 0.708 29 | 05 0.622 21.000 6.857 0.992 0.453 30 | 07 0.885 12.369 1.754 0.935 0.841 31 | 09 0.302 16.432 3.876 0.626 0.199 32 | 10 0.538 31.032 6.885 0.976 0.371 33 | 11 0.513 23.431 4.327 0.794 0.379 34 | 12 0.781 24.556 3.311 0.947 0.665 35 | 13 0.826 22.450 2.691 0.872 0.784 36 | 15 0.808 11.225 2.075 0.760 0.862 37 | 17 0.532 65.038 7.588 0.831 0.391 38 | 18 0.816 21.213 2.345 0.810 0.822 39 | 22 0.408 36.249 6.638 0.296 0.660 40 | 23 0.673 17.234 2.436 0.663 0.684 41 | 25 0.621 28.618 4.423 0.583 0.665 42 | 26 0.520 19.209 5.005 0.361 0.927 43 | DM average 0.643602859267 +/- 0.168065065249 (Median: 0.622024471635) 44 | HD average 25.4155934319 +/- 12.5716987916 (Median: 22.4499443206) 45 | ASSD average 4.26241033967 +/- 1.87614017299 (Median: 3.87577308504) 46 | Prec. average 0.759066397793 +/- 0.208591520379 (Median: 0.809927360775) 47 | Rec. average 0.627438310133 +/- 0.210321711517 (Median: 0.664652567976) 48 | -------------------------------------------------------------------------------- /logs/eval.rdf.all.depth9.log: -------------------------------------------------------------------------------- 1 | INFO: Reverting segmentations.... 2 | INFO: Evaluating in original space... 3 | Metrics: 4 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 5 | 03 0.730 32.467 4.968 0.975 0.583 6 | 05 0.547 24.183 8.393 0.999 0.377 7 | 07 0.830 15.330 2.018 0.969 0.726 8 | 09 0.519 13.991 2.214 0.865 0.370 9 | 10 0.442 28.810 7.867 0.944 0.289 10 | 11 0.477 45.226 6.136 0.846 0.332 11 | 12 0.641 27.500 4.962 0.920 0.492 12 | 13 0.798 23.620 2.615 0.876 0.733 13 | 15 0.743 17.782 2.161 0.704 0.788 14 | 17 0.558 58.415 6.356 0.962 0.393 15 | 18 0.835 16.500 1.304 0.867 0.806 16 | 22 0.271 35.353 7.783 0.196 0.438 17 | 23 0.687 15.198 1.902 0.730 0.648 18 | 25 0.654 34.117 3.280 0.672 0.636 19 | 26 0.588 20.652 3.236 0.490 0.736 20 | DM average 0.621400831584 +/- 0.152721713975 (Median: 0.641362459277) 21 | HD average 27.2762451607 +/- 12.0315214084 (Median: 24.1833476758) 22 | ASSD average 4.34634154601 +/- 2.36541039595 (Median: 3.27997763594) 23 | Prec. average 0.801087827224 +/- 0.21108057361 (Median: 0.867031924982) 24 | Rec. average 0.556439054164 +/- 0.174485782578 (Median: 0.583434001046) 25 | INFO: Evaluating in sequence space.. 26 | Metrics: 27 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 28 | 03 0.735 33.136 5.108 0.962 0.594 29 | 05 0.561 26.153 8.105 0.997 0.390 30 | 07 0.856 15.000 2.167 0.969 0.766 31 | 09 0.566 11.225 2.594 0.862 0.421 32 | 10 0.466 27.821 7.706 0.977 0.306 33 | 11 0.521 45.497 6.566 0.904 0.366 34 | 12 0.696 28.302 4.477 0.988 0.538 35 | 13 0.832 23.622 2.705 0.885 0.785 36 | 15 0.813 11.225 2.204 0.754 0.883 37 | 17 0.564 60.374 7.704 0.957 0.400 38 | 18 0.851 15.297 1.843 0.861 0.841 39 | 22 0.353 33.136 7.259 0.255 0.571 40 | 23 0.692 15.000 2.349 0.721 0.665 41 | 25 0.655 30.741 4.100 0.658 0.651 42 | 26 0.655 20.125 3.533 0.533 0.850 43 | DM average 0.654313329206 +/- 0.144754855803 (Median: 0.655063291139) 44 | HD average 26.4435958188 +/- 12.9744456594 (Median: 26.1533936612) 45 | ASSD average 4.56127927904 +/- 2.25224794745 (Median: 4.10034248664) 46 | Prec. average 0.81888259623 +/- 0.200308245467 (Median: 0.884595162986) 47 | Rec. average 0.601750053429 +/- 0.18813419744 (Median: 0.594028169014) 48 | 49 | -------------------------------------------------------------------------------- /logs/et_rdf_alter.log: -------------------------------------------------------------------------------- 1 | INFO: Reverting segmentations.... 2 | INFO: Evaluating in original space... 3 | Metrics: 4 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 5 | 03 0.779 30.848 3.971 0.963 0.654 6 | 05 0.617 23.162 7.282 0.998 0.447 7 | 07 0.860 12.655 1.544 0.940 0.792 8 | 09 0.607 12.087 1.633 0.744 0.512 9 | 10 0.534 27.244 6.816 0.938 0.374 10 | 11 0.489 29.556 4.458 0.868 0.341 11 | 12 0.735 23.866 3.596 0.890 0.626 12 | 13 0.821 21.302 2.207 0.864 0.783 13 | 15 0.737 17.782 2.118 0.689 0.792 14 | 17 0.605 60.830 6.161 0.905 0.454 15 | 18 0.842 16.500 1.172 0.854 0.831 16 | 22 0.296 38.136 8.292 0.215 0.474 17 | 23 0.725 15.643 1.693 0.715 0.735 18 | 25 0.627 34.955 3.385 0.708 0.562 19 | 26 0.515 18.900 3.788 0.376 0.816 20 | DM average 0.652551512884 +/- 0.149555626186 (Median: 0.626808034958) 21 | HD average 25.5643781827 +/- 12.1030647188 (Median: 23.1617647469) 22 | ASSD average 3.87450343955 +/- 2.22200943711 (Median: 3.59560936179) 23 | Prec. average 0.777830975874 +/- 0.213002474849 (Median: 0.864152362369) 24 | Rec. average 0.61270824889 +/- 0.166284769267 (Median: 0.625748143163) 25 | INFO: Evaluating in sequence space.. 26 | Metrics: 27 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 28 | 03 0.788 31.464 4.133 0.956 0.671 29 | 05 0.633 24.372 6.842 0.996 0.464 30 | 07 0.886 13.748 1.777 0.941 0.836 31 | 09 0.667 10.817 2.312 0.774 0.585 32 | 10 0.560 30.150 6.515 0.974 0.393 33 | 11 0.535 29.698 4.654 0.929 0.375 34 | 12 0.801 24.556 3.080 0.957 0.689 35 | 13 0.847 22.450 2.502 0.867 0.827 36 | 15 0.814 11.225 2.126 0.749 0.891 37 | 17 0.614 62.570 7.295 0.905 0.465 38 | 18 0.854 15.000 1.820 0.848 0.861 39 | 22 0.381 35.749 7.352 0.276 0.612 40 | 23 0.729 15.297 2.139 0.701 0.760 41 | 25 0.647 31.177 4.098 0.711 0.594 42 | 26 0.562 19.209 4.574 0.404 0.921 43 | DM average 0.687818221012 +/- 0.139794800326 (Median: 0.666666666667) 44 | HD average 25.1654853691 +/- 12.6687941864 (Median: 24.3721152139) 45 | ASSD average 4.08130701926 +/- 1.9966164099 (Median: 4.09801205292) 46 | Prec. average 0.799251002133 +/- 0.203976439752 (Median: 0.867449254096) 47 | Rec. average 0.662951100183 +/- 0.177523678067 (Median: 0.670647887324) 48 | 49 | PARAMS: 50 | bootstrap=true 51 | max_features=None 52 | -------------------------------------------------------------------------------- /logs/et_rdf_alter.log~: -------------------------------------------------------------------------------- 1 | INFO: Reverting segmentations.... 2 | INFO: Evaluating in original space... 3 | Metrics: 4 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 5 | 03 0.779 30.848 3.971 0.963 0.654 6 | 05 0.617 23.162 7.282 0.998 0.447 7 | 07 0.860 12.655 1.544 0.940 0.792 8 | 09 0.607 12.087 1.633 0.744 0.512 9 | 10 0.534 27.244 6.816 0.938 0.374 10 | 11 0.489 29.556 4.458 0.868 0.341 11 | 12 0.735 23.866 3.596 0.890 0.626 12 | 13 0.821 21.302 2.207 0.864 0.783 13 | 15 0.737 17.782 2.118 0.689 0.792 14 | 17 0.605 60.830 6.161 0.905 0.454 15 | 18 0.842 16.500 1.172 0.854 0.831 16 | 22 0.296 38.136 8.292 0.215 0.474 17 | 23 0.725 15.643 1.693 0.715 0.735 18 | 25 0.627 34.955 3.385 0.708 0.562 19 | 26 0.515 18.900 3.788 0.376 0.816 20 | DM average 0.652551512884 +/- 0.149555626186 (Median: 0.626808034958) 21 | HD average 25.5643781827 +/- 12.1030647188 (Median: 23.1617647469) 22 | ASSD average 3.87450343955 +/- 2.22200943711 (Median: 3.59560936179) 23 | Prec. average 0.777830975874 +/- 0.213002474849 (Median: 0.864152362369) 24 | Rec. average 0.61270824889 +/- 0.166284769267 (Median: 0.625748143163) 25 | INFO: Evaluating in sequence space.. 26 | Metrics: 27 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 28 | 03 0.788 31.464 4.133 0.956 0.671 29 | 05 0.633 24.372 6.842 0.996 0.464 30 | 07 0.886 13.748 1.777 0.941 0.836 31 | 09 0.667 10.817 2.312 0.774 0.585 32 | 10 0.560 30.150 6.515 0.974 0.393 33 | 11 0.535 29.698 4.654 0.929 0.375 34 | 12 0.801 24.556 3.080 0.957 0.689 35 | 13 0.847 22.450 2.502 0.867 0.827 36 | 15 0.814 11.225 2.126 0.749 0.891 37 | 17 0.614 62.570 7.295 0.905 0.465 38 | 18 0.854 15.000 1.820 0.848 0.861 39 | 22 0.381 35.749 7.352 0.276 0.612 40 | 23 0.729 15.297 2.139 0.701 0.760 41 | 25 0.647 31.177 4.098 0.711 0.594 42 | 26 0.562 19.209 4.574 0.404 0.921 43 | DM average 0.687818221012 +/- 0.139794800326 (Median: 0.666666666667) 44 | HD average 25.1654853691 +/- 12.6687941864 (Median: 24.3721152139) 45 | ASSD average 4.08130701926 +/- 1.9966164099 (Median: 4.09801205292) 46 | Prec. average 0.799251002133 +/- 0.203976439752 (Median: 0.867449254096) 47 | Rec. average 0.662951100183 +/- 0.177523678067 (Median: 0.670647887324) 48 | 49 | PARAMS: 50 | bootstrap=ture 51 | max_features=None 52 | -------------------------------------------------------------------------------- /scripts/make_spm_segment.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | #### 4 | # Creates a Matlab script to segment the tissues from a T2 or T1 image. 5 | # The method used is: SPM Segment 6 | # arg1: the T1/T2 image to segment 7 | # arg2: the associated brain mask 8 | # arg3: the target matlab script file 9 | #### 10 | 11 | import sys 12 | 13 | def main(): 14 | tfile = sys.argv[1] 15 | mask = sys.argv[2] 16 | target = sys.argv[3] 17 | 18 | script = script_template.format(tfile, mask, tfile, mask) 19 | 20 | with open(target, 'w') as f: 21 | f.write(script) 22 | 23 | script_template = """ 24 | % Script to segment the tissues from image {} using brain mask {}. 25 | 26 | addpath '/home/maier/Applications/spm8' 27 | 28 | matlabbatch{{1}}.spm.spatial.preproc.data = {{'{},1'}}; 29 | matlabbatch{{1}}.spm.spatial.preproc.output.GM = [0 0 1]; 30 | matlabbatch{{1}}.spm.spatial.preproc.output.WM = [0 0 1]; 31 | matlabbatch{{1}}.spm.spatial.preproc.output.CSF = [0 0 1]; 32 | matlabbatch{{1}}.spm.spatial.preproc.output.biascor = 0; 33 | matlabbatch{{1}}.spm.spatial.preproc.output.cleanup = 0; 34 | matlabbatch{{1}}.spm.spatial.preproc.opts.tpm = {{ 35 | '/home/maier/Applications/spm8/tpm/grey.nii' 36 | '/home/maier/Applications/spm8/tpm/white.nii' 37 | '/home/maier/Applications/spm8/tpm/csf.nii' 38 | }}; 39 | matlabbatch{{1}}.spm.spatial.preproc.opts.ngaus = [2 40 | 2 41 | 2 42 | 4]; 43 | matlabbatch{{1}}.spm.spatial.preproc.opts.regtype = ''; 44 | matlabbatch{{1}}.spm.spatial.preproc.opts.warpreg = 1; 45 | matlabbatch{{1}}.spm.spatial.preproc.opts.warpco = 25; 46 | matlabbatch{{1}}.spm.spatial.preproc.opts.biasreg = 0; 47 | matlabbatch{{1}}.spm.spatial.preproc.opts.biasfwhm = 60; 48 | matlabbatch{{1}}.spm.spatial.preproc.opts.samp = 3; 49 | matlabbatch{{1}}.spm.spatial.preproc.opts.msk = {{'{},1'}}; 50 | 51 | spm('defaults', 'FMRI'); 52 | spm_jobman('initcfg'); 53 | spm_jobman('serial', matlabbatch); 54 | 55 | exit; 56 | """ 57 | 58 | if __name__ == "__main__": 59 | main() 60 | -------------------------------------------------------------------------------- /scripts/extract_features.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | """ 4 | Extract features from an supplied multi-spectral image according to a config file and saves them under the supplied target directory. 5 | arg1: folder with image channels 6 | arg2: mask image, features are only extracted for voxels where 1 7 | arg3: the target folder to store the extracted features 8 | arg4: the config file, containing a struct called features_to_extract that follows a special syntax 9 | 10 | Note: Does not overwrite existing feature files. 11 | """ 12 | 13 | import os 14 | import sys 15 | import imp 16 | import numpy 17 | import itertools 18 | 19 | from medpy.io import load, header 20 | 21 | # configuration 22 | trg_dtype = numpy.float32 23 | 24 | def main(): 25 | # loading the features to extract 26 | d, m = os.path.split(os.path.splitext(sys.argv[4])[0]) 27 | f, filename, desc = imp.find_module(m, [d]) 28 | features_to_extract = imp.load_module(m, f, filename, desc).features_to_extract 29 | 30 | # loading the image mask 31 | m = load(sys.argv[2])[0].astype(numpy.bool) 32 | 33 | # extracting the required features and saving them 34 | for sequence, function_call, function_arguments, voxelspacing in features_to_extract: 35 | if not isfv(sys.argv[3], sequence, function_call, function_arguments): 36 | #print sequence, function_call.__name__, function_arguments 37 | i, h = load('{}/{}.nii.gz'.format(sys.argv[1], sequence)) 38 | call_arguments = list(function_arguments) 39 | if voxelspacing: call_arguments.append(header.get_pixel_spacing(h)) 40 | call_arguments.append(m) 41 | fv = function_call(i, *call_arguments) 42 | savefv(fv, sys.argv[3], sequence, function_call, function_arguments) 43 | 44 | def savefv(fv, trgdir, seq, fcall, fargs): 45 | """Saves the supplied feature vector under a fixed naming rule.""" 46 | name = 'feature.{}.{}.{}'.format(seq, fcall.func_name, '_'.join(['arg{}'.format(i) for i in fargs])) 47 | with open('{}/{}.npy'.format(trgdir, name), 'wb') as f: 48 | numpy.save(f, fv.astype(trg_dtype)) 49 | 50 | def isfv(trgdir, seq, fcall, fargs): 51 | name = 'feature.{}.{}.{}'.format(seq, fcall.func_name, '_'.join(['arg{}'.format(i) for i in fargs])) 52 | return os.path.exists('{}/{}.npy'.format(trgdir, name)) 53 | 54 | if __name__ == "__main__": 55 | main() 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /clone.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ###### 4 | # Clone directory for experiments (first phase) 5 | # call with: source .sh, otherwise environement variables won't get set 6 | # MedPy requires: 7 | # sudo apt-get install build-essential python-dev python-numpy python-setuptools python-scipy libatlas-dev python-pip 8 | # pip install -U nibabel 9 | # pip install -U scikit-learn 10 | # 11 | # cp /share/data_humbug1/maier/Temp_Pipeline/Pipeline/clone.sh . 12 | # 13 | # export PYTHONPATH=${PYTHONPATH}:/home/maier/Libraries/Python:/home/maier/Workspacepython/medpy 14 | # export PATH=$PATH:/home/maier/Workspacepython/medpy/bin 15 | ###### 16 | 17 | base="/share/data_humbug1/maier/Temp_Pipeline/NeuroImagePipeline/" 18 | 19 | cp ${base}/config.sh . 20 | cp ${base}/featureconfig.py . 21 | ln -s ${base}/include.sh . 22 | 23 | ln -s ${base}/logs . 24 | #ln -s ${base}/scripts . 25 | cp -r ${base}/scripts . 26 | 27 | ln -s ${base}/00original 28 | ln -s ${base}/01flairspace 29 | ln -s ${base}/02flairskullstripped 30 | ln -s ${base}/03biasfieldcorrected 31 | ln -s ${base}/04flairintensitrangestandardization 32 | ln -s ${base}/05flairfeatures 33 | #ln -s ${base}/06samplesets 34 | #ln -s ${base}/07forests 35 | #ln -s ${base}/08flairlesionsegmentation 36 | 37 | ln -s ${base}/100gtsegmentations 38 | ln -s ${base}/102flairbrainmasks 39 | ln -s ${base}/101flairsegmentations 40 | 41 | #mkdir 01flairspace 42 | #mkdir 02flairskullstripped 43 | #mkdir 03biasfieldcorrected 44 | #mkdir 04flairintensitrangestandardization 45 | #mkdir 05flairfeatures 46 | mkdir 06samplesets 47 | mkdir 07forests 48 | mkdir 08flairlesionsegmentation 49 | 50 | #mkdir 102flairbrainmasks 51 | #mkdir 101flairsegmentations 52 | 53 | #ln -s ${base}/pop_sequencespace.sh . 54 | #ln -s ${base}/pop_sequenceskullstripped.sh . 55 | #ln -s ${base}/pop_sequencesegmentations.sh . 56 | #ln -s ${base}/pop_sequencebiasfieldcorrected.sh . 57 | #ln -s ${base}/pop_sequenceintensitrangestandardization.sh . 58 | #ln -s ${base}/pop_sequencefeatures.sh . 59 | ln -s ${base}/pop_sequencesamplesets.sh . 60 | ln -s ${base}/pop_sequencetrainforests.sh . 61 | ln -s ${base}/pop_sequencelesionsegmentation.sh . 62 | 63 | ln -s ${base}/evaluate_original.sh . 64 | cp ${base}/execute.sh . 65 | 66 | export PYTHONPATH=/home/maier/Workspacepython/medpy 67 | export PATH=${PATH}:/home/maier/Workspacepython/medpy/bin 68 | -------------------------------------------------------------------------------- /experiments/exp01a.cycle01.description: -------------------------------------------------------------------------------- 1 | @see LesionMaskingInIsotropicFlair.odt for overview 2 | 3 | In this experiments, a number of feature selections are considered for their ability to discriminate between lesion and non-lesion voxels. 4 | The sets tested are: 5 | - intensity only 6 | - local_mean_gauss 3 7 | - local_mean_gauss 5 8 | - local_mean_gauss 7 9 | - local_mean_gauss 3+5+7 10 | - local_histogram 11bins/10mm 11 | - local_histogram 11bins/20mm 12 | - local_histogram 11bins/30mm 13 | - local_histogram 11bins/10+20+30mm 14 | - median 7 15 | - gaussian_gradient_magnitude 5 16 | - local_mean_gauss 3+5+7 & local_histogram 11bins/?mm 17 | - all together 18 | - all together plus centerdistance2D along all dimensions 19 | 20 | Evaluation: 21 | a) Difference with (tranformed) ground truth 22 | b) Visual examination 23 | 24 | Other settings: 25 | - training sample set size = 250.000 26 | - post-processing: hole closing only 27 | - pre-processing: intensity range std (ala Oskar) only 28 | - re-sampling: iso, 2x2x2 29 | 30 | Results: 31 | @see exp01a.cycle.all 32 | @see exp01a.cycle.int_lmg3_lh1111.log 33 | 34 | Interpretation: 35 | # exp01a.cycle.all 36 | teils sehr gut getroffen, mit nur sehr wenigen, kleinen outliern 37 | aber teilweise auch nicht so gut, gerade bei kleineren Läsionen 38 | ein großer Hang zu Untersegmentierung 39 | andere WMH gar nicht so oft gefunden, viel wurden sie ignoriert 40 | ungenügender Skull-Strip ist immer noch ein Problem, htps. an der Schädeldecke 41 | viele False-Positive auch im Kleinhirn 42 | 43 | Conclusion: 44 | Ein Feature wird benötigt, dass hilft das Kleinhirn und die Schädeldecke auszuschließen 45 | => Distance from brain center? Or gravity center? Prüfen, wo die jeweils liegen! Eventuell andere Methode um Zentrum des Cerebrum zu finden. 46 | Kleine Fehlsegmentierungen 47 | => Entfernen indem binäre Objekte < 4mm entfernt werden 48 | Untersegmentierung 49 | => Dilation (in 2D? 3D?) mit ein paar wenige Iterations (aber nach entfernen der kleinen Objekte + cut off by brain-mask) 50 | 51 | Machines used in the experiments: 52 | - humbug1 53 | - humbug2 54 | - rumpel1 55 | - mumpitz1 56 | - oskar2 57 | - bibo1 58 | - hastig1 59 | - hastig2 60 | - schorsch1 61 | - schorsch2 62 | 63 | 64 | No-space maschines: 65 | - mumpitz2 66 | - rumpel2 67 | - oskar1 68 | - bibo2 69 | -------------------------------------------------------------------------------- /logs/exp00.j.log: -------------------------------------------------------------------------------- 1 | INFO: Reverting segmentations.... 2 | INFO: Evaluating in original space... 3 | Metrics: 4 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 5 | 03 0.761 30.994 4.435 0.956 0.632 6 | 05 0.572 24.296 7.850 0.997 0.401 7 | 06 0.705 25.250 3.467 0.942 0.563 8 | 07 0.854 11.283 1.681 0.939 0.783 9 | 09 0.654 11.283 1.415 0.719 0.599 10 | 10 0.640 23.096 5.390 0.943 0.484 11 | 11 0.319 46.086 7.143 0.941 0.192 12 | 12 0.709 22.908 4.041 0.870 0.598 13 | 13 0.794 21.302 2.648 0.867 0.733 14 | 15 0.719 18.899 2.465 0.701 0.737 15 | 17 0.789 13.588 2.485 0.746 0.837 16 | 18 0.834 16.500 1.305 0.891 0.784 17 | 20 0.736 116.998 17.250 0.701 0.773 18 | 21 0.827 17.759 1.528 0.927 0.747 19 | 22 0.113 40.664 11.500 0.092 0.146 20 | 23 0.696 18.204 1.952 0.738 0.659 21 | 25 0.640 34.452 3.323 0.651 0.630 22 | 26 0.560 18.925 3.545 0.422 0.832 23 | 29 0.607 42.197 4.552 0.759 0.506 24 | DM average 0.659387808811 +/- 0.176708680231 (Median: 0.704626175281) 25 | HD average 29.1939229637 +/- 22.9579296627 (Median: 22.9077081359) 26 | ASSD average 4.63036626252 +/- 3.89623922204 (Median: 3.46742849448) 27 | Prec. average 0.779124405229 +/- 0.214023930063 (Median: 0.866774776344) 28 | Rec. average 0.612452443851 +/- 0.19249253917 (Median: 0.63232695671) 29 | INFO: Evaluating in sequence space.. 30 | Metrics: 31 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 32 | 03 0.773 32.311 4.402 0.953 0.651 33 | 05 0.585 26.325 7.559 0.995 0.414 34 | 06 0.720 24.556 4.155 0.954 0.578 35 | 07 0.869 10.817 2.062 0.929 0.816 36 | 09 0.721 9.950 1.947 0.765 0.682 37 | 10 0.670 22.450 5.027 0.976 0.510 38 | 11 0.344 48.094 8.001 0.991 0.208 39 | 12 0.773 23.622 3.498 0.931 0.661 40 | 13 0.831 22.045 2.706 0.882 0.785 41 | 15 0.803 13.748 2.262 0.764 0.846 42 | 17 0.785 15.000 3.097 0.730 0.849 43 | 18 0.835 15.000 1.915 0.873 0.800 44 | 20 0.804 114.630 15.058 0.768 0.844 45 | 21 0.843 17.748 2.143 0.922 0.777 46 | 22 0.182 38.066 10.417 0.147 0.240 47 | 23 0.696 17.493 2.436 0.721 0.673 48 | 25 0.664 30.741 4.032 0.658 0.669 49 | 26 0.601 17.748 4.198 0.447 0.919 50 | 29 0.646 42.532 4.756 0.799 0.542 51 | DM average 0.691863599527 +/- 0.169492688293 (Median: 0.721088435374) 52 | HD average 28.5723857285 +/- 22.7385097667 (Median: 22.4499443206) 53 | ASSD average 4.71947278455 +/- 3.30953258457 (Median: 4.03154261849) 54 | Prec. average 0.800283038197 +/- 0.205098293431 (Median: 0.87323943662) 55 | Rec. average 0.65597964147 +/- 0.195921496632 (Median: 0.672672672673) 56 | -------------------------------------------------------------------------------- /scripts/parse_time.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | """ 4 | Parses an evaluation result produced by evaluate.sh resp. 5 | evaluate_original.sh and converts it into csv or latex conform 6 | output. Output is written to stdout. 7 | """ 8 | 9 | # build-in modules 10 | import argparse 11 | import logging 12 | 13 | # third-party modules 14 | import numpy 15 | 16 | # path changes 17 | 18 | # own modules 19 | from medpy.core import Logger 20 | from medpy.io import load, save 21 | 22 | # constants 23 | EXLUDED_FILES = ['37', '44'] 24 | 25 | 26 | # information 27 | __author__ = "Oskar Maier" 28 | __version__ = "r0.1.0, 2014-06-04" 29 | __email__ = "oskar.maier@googlemail.com" 30 | __status__ = "Release" 31 | __description__ = """ 32 | Parses multiple time results and prints them in orderly fashion. 33 | 34 | Copyright (C) 2013 Oskar Maier 35 | This program comes with ABSOLUTELY NO WARRANTY; This is free software, 36 | and you are welcome to redistribute it under certain conditions; see 37 | the LICENSE file or for details. 38 | """ 39 | 40 | # code 41 | def main(): 42 | args = getArguments(getParser()) 43 | 44 | # prepare logger 45 | logger = Logger.getInstance() 46 | if args.debug: logger.setLevel(logging.DEBUG) 47 | elif args.verbose: logger.setLevel(logging.INFO) 48 | 49 | for fn in args.inputs: 50 | print fn 51 | with open(fn, 'r') as f: 52 | for line in f.readlines(): 53 | line = line.strip() 54 | if 'elapsed' in line: 55 | chunks = line.split() 56 | print chunks[0], chunks[2], chunks[3] 57 | elif 'real' in line: 58 | _tmp = line.split()[1] 59 | elif 'user' in line: 60 | print line.split()[1], _tmp 61 | 62 | def getArguments(parser): 63 | "Provides additional validation of the arguments collected by argparse." 64 | return parser.parse_args() 65 | 66 | def getParser(): 67 | "Creates and returns the argparse parser object." 68 | parser = argparse.ArgumentParser(description=__description__) 69 | parser.add_argument('inputs', nargs='+', help='The input time files.') 70 | parser.add_argument('-v', dest='verbose', action='store_true', help='Display more information.') 71 | parser.add_argument('-d', dest='debug', action='store_true', help='Display debug information.') 72 | return parser 73 | 74 | if __name__ == "__main__": 75 | main() 76 | -------------------------------------------------------------------------------- /config.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ###################### 4 | # Configuration file # 5 | ###################### 6 | 7 | ## changelog 8 | # 2014-05-08 created 9 | 10 | # image array 11 | images=('03' '04' '05' '06' '07' '08' '09' '10' '11' '12' '13' '15' '17' '18' '19' '20' '21' '23' '25' '26' '28' '29' '30' '31' '32' '33' '34' '35' '36' '37' '39' '40' '41' '42' '43' '44' '45') # NeuroImage 12 | 13 | #images=('03' '04' '05' '06' '07' '08' '09' '10' '11' '12' '13' '15' '17' '18' '19' '20' '21' '22' '23' '25' '26' '28' '29' '30' '31' '32' '33' '34' '35' '36' '37' '39' '40' '41' '42' '43' '44' '45') # FLAIR 14 | 15 | #images=('03' '05' '07' '09' '10' '11' '12' '13' '15' '17' '18' '22' '23' '25' '26' '31' '32' '33' '34' '35' '36' '37' '39' '40' '41' '42' '43' '44' '45') # DW/ADC 16 | #images=('03' '04' '05' '06' '07' '08' '09' '10' '11' '12' '13' '15' '17' '18' '20' '21' '22' '23' '25' '26' '28' '29') # T1_SAG_TFE 17 | #images=('03' '05' '06' '07' '09' '10' '11' '12' '13' '15' '17' '18' '19' '20' '21' '22' '23' '25' '26' '29' '30' '32' '33' '34' '35' '36' '37' '39' '40' '41' '42' '43' '44' '45') # T2_SAG_TSE 18 | 19 | #images=('03' '05' '07' '09' '10' '11' '12' '13' '15' '17' '18' '22' '23' '25' '26') # DW/ADC + T1_SAG_TFE 20 | #images=('03' '05' '07' '09' '10' '11' '12' '13' '15' '17' '18' '22' '23' '25' '26' '32' '33' '34' '35' '36' '37' '39' '40' '41' '42' '43' '44' '45') # DW/ADC + T2_SAG_TSE 21 | #images=('03' '05' '06' '07' '09' '10' '11' '12' '13' '15' '17' '18' '20' '21' '22' '23' '25' '26' '29') # T1_SAG_TFE + T2_SAG_TSE 22 | 23 | #images=('03' '05' '07' '09' '10' '11' '12' '13' '15' '17' '18' '22' '23' '25' '26') # DW/ADC + T1_SAG_TFE + T2_SAG_TSE => j 24 | 25 | #images=('03' '04' '06' '08' '11' '12' '13' '15' '18') # Melanie 26 | 27 | # sequences to use and base sequence 28 | sequences=("flair_tra") # "adc_tra" "dw_tra_b1000_dmean" "t1_tra_ffe" "t2_sag_tse" "t2_tra_ffe" "t2_tra_tse" "t1_sag_tfe") # sequences to use 29 | basesequence="flair_tra" # base sequence for all operation sin sequence space 30 | 31 | # sequence space settings 32 | isotropic=1 # 0/1 to disable/enable pre-registration resampling of base sequence to isotropic spacing 33 | isotropicspacing=3 # the target isotropic spacing in mm 34 | 35 | # config file with feature (1) to extract and (2) to create the training sample from 36 | featurecnf="featureconfig.py" 37 | 38 | # training sample size 39 | samplesize=250000 40 | 41 | # rdf parameters 42 | maxdepth=100 43 | 44 | # post-processing parameters 45 | minimallesionsize=1500 46 | 47 | -------------------------------------------------------------------------------- /pop_sequenceskullstripped.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ##### 4 | # Creates a brain mask using the base sequence image and extracts the 5 | # skull from all sequences volumes. 6 | ##### 7 | 8 | ## Changelog 9 | # 2013-03-25 Adapted to take any sequence as base sequence. 10 | # 2013-11-04 Improved the mechanism and seperated the brain mask location from the skull-stripped images. 11 | # 2013-10-16 created 12 | 13 | # include shared information 14 | source $(dirname $0)/include.sh 15 | 16 | # functions 17 | ### 18 | # Compute a brain mask using the base sequence 19 | ### 20 | function compute_brainmask () 21 | { 22 | # grab parameters 23 | i=$1 24 | 25 | # created required directories 26 | mkdircond ${sequenceskullstripped}/${i} 27 | # continue if target file already exists 28 | if [ -f "${sequencebrainmasks}/${i}.${imgfiletype}" ]; then 29 | return 30 | fi 31 | # compute brain mask 32 | log 1 "Computing brain mask for ${sequencespace}/${i}/${basesequence}.${imgfiletype}" "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 33 | runcond "fsl5.0-bet ${sequencespace}/${i}/${basesequence}.${imgfiletype} ${sequenceskullstripped}/${i}/${basesequence}.${imgfiletype} -m -R" /dev/null 34 | runcond "mv ${sequenceskullstripped}/${i}/${basesequence}_mask.${imgfiletype} ${sequencebrainmasks}/${i}.${imgfiletype}" 35 | } 36 | 37 | # main code 38 | log 2 "Computing brain masks on base sequence ${basesequence}" "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 39 | parallelize compute_brainmask ${threadcount} images[@] 40 | 41 | log 2 "Applying brainmask to remaining spectra" "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 42 | for i in "${images[@]}"; do 43 | for s in "${sequences[@]}"; do 44 | # skip if base sequence 45 | if [ "${s}" == "${basesequence}" ]; then 46 | continue 47 | fi 48 | 49 | srcfile="${sequencespace}/${i}/${s}.${imgfiletype}" 50 | trgfile="${sequenceskullstripped}/${i}/${s}.${imgfiletype}" 51 | 52 | # continue if target file already exists 53 | if [ -f "${trgfile}" ]; then 54 | log 1 "Target file ${trgfile} already exists. Skipping." "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 55 | continue 56 | fi 57 | # continue and warn if source file doesn't exists 58 | if [ ! -f "${srcfile}" ]; then 59 | log 3 "Source file ${srcfile} does not exist. Skipping." "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 60 | continue 61 | fi 62 | 63 | runcond "${scripts}/apply_binary_mask.py ${srcfile} ${sequencebrainmasks}/${i}.${imgfiletype} ${trgfile}" /dev/null 64 | done 65 | done 66 | log 2 "Done." "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 67 | 68 | -------------------------------------------------------------------------------- /logs/exp00.e.log: -------------------------------------------------------------------------------- 1 | INFO: Reverting segmentations.... 2 | INFO: Evaluating in original space... 3 | Metrics: 4 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 5 | 03 0.717 31.931 5.217 0.968 0.570 6 | 04 0.745 10.920 2.073 0.755 0.735 7 | 05 0.557 23.768 7.817 0.997 0.387 8 | 06 0.714 23.125 3.388 0.923 0.583 9 | 07 0.861 10.733 1.625 0.933 0.799 10 | 08 0.643 26.559 6.138 0.928 0.491 11 | 09 0.610 11.557 2.087 0.594 0.626 12 | 10 0.616 24.216 5.627 0.940 0.459 13 | 11 0.497 42.735 5.553 0.899 0.344 14 | 12 0.724 23.288 3.857 0.846 0.633 15 | 13 0.790 21.863 2.769 0.888 0.711 16 | 15 0.705 19.963 2.630 0.717 0.694 17 | 17 0.785 13.287 2.629 0.716 0.867 18 | 18 0.802 16.719 1.499 0.879 0.738 19 | 20 0.711 118.183 21.222 0.628 0.819 20 | 21 0.849 17.759 1.276 0.909 0.796 21 | 22 0.149 40.664 10.874 0.121 0.194 22 | 23 0.705 18.204 1.740 0.763 0.655 23 | 25 0.617 29.285 2.676 0.572 0.670 24 | 26 0.634 18.723 2.813 0.514 0.828 25 | 28 0.746 28.113 2.865 0.835 0.675 26 | 29 0.671 39.794 3.575 0.795 0.581 27 | DM average 0.674985257258 +/- 0.144763681147 (Median: 0.708179779634) 28 | HD average 27.790463879 +/- 21.6784753876 (Median: 23.2066232452) 29 | ASSD average 4.54326648144 +/- 4.29136245466 (Median: 2.83905159318) 30 | Prec. average 0.778133033713 +/- 0.196395477941 (Median: 0.84023381667) 31 | Rec. average 0.629763399702 +/- 0.166976988546 (Median: 0.662619912849) 32 | INFO: Evaluating in sequence space.. 33 | Metrics: 34 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 35 | 03 0.726 33.000 5.179 0.960 0.583 36 | 04 0.772 11.225 2.376 0.759 0.786 37 | 05 0.572 25.981 7.729 0.994 0.401 38 | 06 0.741 23.431 3.788 0.949 0.607 39 | 07 0.878 10.817 1.932 0.925 0.836 40 | 08 0.677 24.187 5.868 0.967 0.521 41 | 09 0.630 10.817 2.675 0.603 0.659 42 | 10 0.649 23.431 5.275 0.977 0.486 43 | 11 0.530 45.000 6.370 0.937 0.369 44 | 12 0.793 23.622 3.235 0.912 0.701 45 | 13 0.819 23.431 2.786 0.895 0.755 46 | 15 0.805 15.297 2.205 0.797 0.814 47 | 17 0.779 15.000 3.245 0.698 0.881 48 | 18 0.848 15.588 1.750 0.909 0.795 49 | 20 0.777 116.228 17.865 0.686 0.895 50 | 21 0.874 17.234 1.794 0.915 0.837 51 | 22 0.228 38.066 9.704 0.183 0.305 52 | 23 0.713 17.493 2.266 0.753 0.677 53 | 25 0.668 23.622 3.175 0.604 0.748 54 | 26 0.679 17.234 3.389 0.542 0.910 55 | 28 0.802 30.299 2.954 0.888 0.731 56 | 29 0.705 38.536 3.882 0.834 0.611 57 | DM average 0.712020273796 +/- 0.138567803624 (Median: 0.73308698454) 58 | HD average 27.2516375369 +/- 21.4493711863 (Median: 23.4307490277) 59 | ASSD average 4.52011202232 +/- 3.53240532315 (Median: 3.24000370673) 60 | Prec. average 0.8039600624 +/- 0.189146153287 (Median: 0.891788244941) 61 | Rec. average 0.677598310193 +/- 0.170845807687 (Median: 0.715968533685) 62 | -------------------------------------------------------------------------------- /scripts/colourconfig.py: -------------------------------------------------------------------------------- 1 | ##### 2 | # Colours as defined in the PP template 3 | ##### 4 | green_lighter = '#edf3d2' 5 | green_light = '#cadd7a' 6 | green = '#a0bb2f' 7 | green_dark = '#788c23' 8 | 9 | yellow_lighter = '#fdf2cb' 10 | yellow_light = '#f9d863' 11 | yellow = '#eab808' 12 | yellow_dark = '#af8a05' 13 | 14 | red_light = '#ea657b' 15 | red = '#c31a35' 16 | red_dark = '#951327' 17 | 18 | orange_light = '#ebaa70' 19 | orange = '#d2731d' 20 | orange_dark = '#9d5615' 21 | 22 | blue_light = '#2fe4ff' 23 | blue = '#0090a5' 24 | blue_dark = '#006b7b' 25 | 26 | blue_text = '#004b54' 27 | 28 | ##### 29 | # Colours defined for usages 30 | ##### 31 | c_text = blue_text 32 | c_plotlines = blue_text 33 | c_highlight_line = red 34 | 35 | c_face_1 = yellow 36 | c_edge_1 = yellow_dark 37 | 38 | c_face_2 = green 39 | c_edge_2 = green_dark 40 | 41 | c_face_3 = red 42 | c_edge_3 = red_dark 43 | 44 | c_face_4 = orange 45 | c_edge_4 = orange_dark 46 | 47 | c_face_5 = blue 48 | c_edge_5 = blue_dark 49 | 50 | ##### 51 | # Function to manipulate objects 52 | ##### 53 | def set_figure_style(figure): 54 | "Change colours and more of figure elements." 55 | import matplotlib 56 | ax = figure.add_subplot(1, 1, 1) 57 | for child in ax.get_children(): 58 | if isinstance(child, matplotlib.spines.Spine): 59 | child.set_color(c_plotlines) 60 | ax.tick_params(axis='x', colors=c_text, labelsize=25) 61 | ax.tick_params(axis='y', colors=c_text, labelsize=25) 62 | 63 | return ax 64 | 65 | def set_min_figure_style(figure): 66 | "Change colours of figure elements." 67 | import matplotlib 68 | ax = figure.add_subplot(1, 1, 1) 69 | for child in ax.get_children(): 70 | if isinstance(child, matplotlib.spines.Spine): 71 | child.set_color(c_plotlines) 72 | ax.tick_params(axis='x', colors=c_text) 73 | ax.tick_params(axis='y', colors=c_text) 74 | 75 | return ax 76 | 77 | def set_boxplot_style(layout): 78 | "Change colours and more of boxplot elements." 79 | for box in layout['boxes']: 80 | box.set_facecolor(c_face_1) 81 | box.set_edgecolor(c_edge_1) 82 | box.set_linewidth(2) 83 | for whisker in layout['whiskers']: 84 | whisker.set_color(c_edge_1) 85 | whisker.set_linewidth(2) 86 | for median in layout['medians']: 87 | median.set_color(c_highlight_line) 88 | median.set_linewidth(2) 89 | for cap in layout['caps']: 90 | cap.set_color(c_edge_1) 91 | cap.set_linewidth(2) 92 | for flier in layout['fliers']: 93 | flier.set(marker='o', color=c_face_2, alpha=1) 94 | flier.set_markersize(10) 95 | flier.set_markeredgecolor(c_edge_2) 96 | 97 | 98 | -------------------------------------------------------------------------------- /pop_segmentations.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ##### 4 | # Link all segmentation images from the image database in a consitent manner. 5 | ##### 6 | 7 | ## Changelog 8 | 9 | # 2014-05-05 Changed to also include the flipping along the mid-saggital plane for every second case. 10 | # 2014-03-25 Changed to copy images and correcting (possibly faulty) voxel spacing 11 | # 2014-03-25 Adapted to work with new case to database case mapping. 12 | # 2013-10-21 created 13 | 14 | # include shared information 15 | source $(dirname $0)/include.sh 16 | 17 | # Constants 18 | basesequenceflipdim="0" 19 | 20 | # Image collection HEOPKS details 21 | c01dir="/imagedata/HEOPKS/segmentation/" 22 | declare -A c01indicesmapping=( ["01"]="01" ["02"]="02" ["03"]="03" ["04"]="04" ["05"]="05" ["06"]="06" ["07"]="07" ["08"]="08" ["09"]="09" ["10"]="10" \ 23 | ["11"]="11" ["12"]="12" ["13"]="13" ["14"]="14" ["15"]="15" ["16"]="16" ["17"]="17" ["18"]="18" ["19"]="19" ["20"]="20" \ 24 | ["21"]="21" ["22"]="22" ["23"]="23" ["24"]="24" ["25"]="25" ["26"]="26" ["27"]="27" ["28"]="28" ["29"]="29" ) 25 | 26 | # Image collection JGABLENTZ details 27 | c02dir="/imagedata/JGABLENTZ/segmentation/" 28 | declare -A c02indicesmapping=( ["30"]="02" ["31"]="08" ["32"]="11" ["33"]="13" ["34"]="14" ["35"]="17" ["36"]="19" ["37"]="20" ["38"]="25" ["39"]="29" \ 29 | ["40"]="30" ["41"]="31" ["42"]="34" ["43"]="47" ["44"]="55" ["45"]="57" ) 30 | 31 | 32 | # main code 33 | log 2 "Copying ground truth images" "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 34 | for i in "${images[@]}"; do 35 | # catch original voxel sapcing of associated flair sequence 36 | vs=( $(voxelspacing "${originals}/${i}/flair_tra.${imgfiletype}") ) 37 | vs=$(joinarr " " ${vs[@]}) 38 | # copy and correct voxel spacing 39 | if test "${c01indicesmapping[${i}]+isset}"; then 40 | runcond "medpy_set_pixel_spacing.py ${c01dir}/${c01indicesmapping[${i}]}.${imgfiletype} ${segmentations}/${i}.${imgfiletype} ${vs[@]}" 41 | elif test "${c02indicesmapping[${i}]+isset}"; then 42 | runcond "medpy_set_pixel_spacing.py ${c02dir}/${c02indicesmapping[${i}]}.${imgfiletype} ${segmentations}/${i}.${imgfiletype} ${vs[@]}" 43 | else 44 | log 3 "No candidate for case id ${i} found in any of the collections. Please check your 'images' array. Skipping." "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 45 | fi 46 | done 47 | 48 | log 2 "Flipping ground truth of every second case in-place along the mid-saggital plane" "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 49 | for (( i = 1 ; i < ${#images[@]} ; i+=2 )) do 50 | f="${segmentations}/${images[$i]}.${imgfiletype}" 51 | if [ -e ${f} ]; then 52 | lnrealize "${f}" 53 | runcond "${scripts}/flip.py ${f} ${basesequenceflipdim}" 54 | fi 55 | done 56 | 57 | log 2 "Done." "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 58 | -------------------------------------------------------------------------------- /scripts/extract_features_sequencespace.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | """ 4 | Extract selected features from an image and save them under a fixed file name structure. 5 | As first argument, supply the source folder with the image channels, as second the mask image and as third the target folder. 6 | Note: Does not overwrite existing feature files. 7 | """ 8 | 9 | import os 10 | import sys 11 | import numpy 12 | import itertools 13 | 14 | from medpy.io import load, header 15 | from medpy.features.intensity import intensities, centerdistance, centerdistance_xdminus1, local_mean_gauss, local_histogram, hemispheric_difference, median, guassian_gradient_magnitude 16 | from medpy.features.intensity import indices as indices_feature 17 | 18 | trg_dtype = numpy.float32 19 | features_to_extract = [ 20 | ('flair_tra', intensities, [], False), 21 | ('flair_tra', local_mean_gauss, [3], True), 22 | ('flair_tra', local_mean_gauss, [5], True), 23 | ('flair_tra', local_mean_gauss, [7], True), 24 | #('flair_tra', guassian_gradient_magnitude, [5], True), 25 | #('flair_tra', median, [7], True), 26 | ('flair_tra', local_histogram, [11, 'image', (0, 100), 5, None, None, 'ignore', 0], False), #11 bins, 5*2=10mm region 27 | ('flair_tra', local_histogram, [11, 'image', (0, 100), 10, None, None, 'ignore', 0], False), #11 bins, 10*2=20mm region 28 | ('flair_tra', local_histogram, [11, 'image', (0, 100), 15, None, None, 'ignore', 0], False), #11 bins, 15*2=30mm region 29 | ('flair_tra', centerdistance_xdminus1, [0], True), 30 | ('flair_tra', centerdistance_xdminus1, [1], True), 31 | ('flair_tra', centerdistance_xdminus1, [2], True) 32 | ] 33 | 34 | def main(): 35 | # loading the image mask 36 | m = load(sys.argv[2])[0].astype(numpy.bool) 37 | 38 | # extracting the required features and saving them 39 | for sequence, function_call, function_arguments, voxelspacing in features_to_extract: 40 | if not isfv(sys.argv[3], sequence, function_call, function_arguments): 41 | #print sequence, function_call.__name__, function_arguments 42 | i, h = load('{}/{}.nii.gz'.format(sys.argv[1], sequence)) 43 | call_arguments = list(function_arguments) 44 | if voxelspacing: call_arguments.append(header.get_pixel_spacing(h)) 45 | call_arguments.append(m) 46 | fv = function_call(i, *call_arguments) 47 | savefv(fv, sys.argv[3], sequence, function_call, function_arguments) 48 | 49 | def savefv(fv, trgdir, seq, fcall, fargs): 50 | """Saves the supplied feature vector under a fixed naming rule.""" 51 | name = 'feature.{}.{}.{}'.format(seq, fcall.func_name, '_'.join(['arg{}'.format(i) for i in fargs])) 52 | with open('{}/{}.npy'.format(trgdir, name), 'wb') as f: 53 | numpy.save(f, fv.astype(trg_dtype)) 54 | 55 | def isfv(trgdir, seq, fcall, fargs): 56 | name = 'feature.{}.{}.{}'.format(seq, fcall.func_name, '_'.join(['arg{}'.format(i) for i in fargs])) 57 | return os.path.exists('{}/{}.npy'.format(trgdir, name)) 58 | 59 | if __name__ == "__main__": 60 | main() 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /pop_sequenceintensitrangestandardization.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ##### 4 | # Standarizes the intensity profiles of all images belonging to the same MRI sequence. 5 | ##### 6 | 7 | ## Changelog 8 | # 2013-03-25 Updated to new structure. 9 | # 2013-11-14 changed script to allow for intensity correction of an image, even if the model already exists 10 | # 2013-11-05 adapted to new brain mask location 11 | # 2013-10-22 created 12 | 13 | # include shared information 14 | source $(dirname $0)/include.sh 15 | 16 | # main code 17 | log 2 "Learning and adapting the intensity profiles" "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 18 | tmpdir=`mktemp -d` 19 | for s in "${sequences[@]}"; do 20 | log 2 "Processing MRI sequence ${s}" "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 21 | 22 | # if target model already exists, skip model creation for the whole sequence and remark upon it 23 | if [ -f "${sequenceintensitrangestandardization}/intensity_model_${s}.pkl" ]; then 24 | log 3 "The intensity model for the MRI sequence ${s} already exists. Skipping the model creation for the whole sequence." "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 25 | else 26 | # collect all the images for training 27 | images_string="" 28 | masks_string="" 29 | for i in "${images[@]}"; do 30 | # if target file already exists, skip model creation for the whole sequence and remark upon it 31 | if [ -f "${sequenceintensitrangestandardization}/${i}/${s}.${imgfiletype}" ]; then 32 | log 3 "One of the target files for the MRI sequence ${s} already exists. Skipping the model creation and image transformation for the whole sequence." "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 33 | continue 2 34 | fi 35 | # add image to list of images to use for training (always use all images) 36 | images_string="${images_string} ${sequencebiasfieldcorrected}/${i}/${s}.${imgfiletype}" 37 | masks_string="${masks_string} ${sequencebrainmasks}/${i}.${imgfiletype}" 38 | done 39 | 40 | # train the model without transforming the images 41 | runcond "medpy_intensity_range_standardization.py --masks ${masks_string} --save-model ${sequenceintensitrangestandardization}/intensity_model_${s}.pkl ${images_string}" 42 | fi 43 | 44 | # transform and post-process the images, them move them to their target location if not already existant 45 | for i in "${images[@]}"; do 46 | mkdircond ${sequenceintensitrangestandardization}/${i} 47 | if [ ! -f "${sequenceintensitrangestandardization}/${i}/${s}.${imgfiletype}" ]; then 48 | runcond "medpy_intensity_range_standardization.py --load-model ${sequenceintensitrangestandardization}/intensity_model_${s}.pkl --masks ${sequencebrainmasks}/${i}.${imgfiletype} --save-images ${tmpdir} ${sequencebiasfieldcorrected}/${i}/${s}.${imgfiletype} -f" 49 | runcond "${scripts}/condenseoutliers.py ${tmpdir}/${s}.${imgfiletype} ${sequenceintensitrangestandardization}/${i}/${s}.${imgfiletype}" 50 | fi 51 | done 52 | 53 | emptydircond ${tmpdir} 54 | done 55 | rmdircond ${tmpdir} 56 | log 2 "Done." "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 57 | 58 | 59 | -------------------------------------------------------------------------------- /logs/exp00.i.log: -------------------------------------------------------------------------------- 1 | INFO: Reverting segmentations.... 2 | INFO: Evaluating in original space... 3 | Metrics: 4 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 5 | 03 0.698 34.204 5.437 0.983 0.541 6 | 05 0.491 30.056 9.251 1.000 0.325 7 | 07 0.846 12.753 1.754 0.940 0.770 8 | 09 0.341 17.224 3.077 0.814 0.216 9 | 10 0.373 43.033 8.651 0.940 0.233 10 | 11 0.671 25.919 2.302 0.882 0.541 11 | 12 0.596 28.668 6.014 0.931 0.438 12 | 13 0.821 23.959 2.294 0.893 0.759 13 | 15 0.747 17.782 2.115 0.748 0.746 14 | 17 0.517 58.415 7.140 0.978 0.351 15 | 18 0.781 16.743 1.626 0.943 0.667 16 | 22 0.292 26.324 6.879 0.204 0.511 17 | 23 0.653 15.643 2.395 0.629 0.679 18 | 25 0.626 30.993 2.916 0.531 0.761 19 | 26 0.581 22.771 3.402 0.475 0.748 20 | 32 0.701 21.637 2.719 0.709 0.692 21 | 33 0.733 22.122 2.901 0.684 0.789 22 | 34 0.719 35.148 3.633 0.696 0.745 23 | 35 0.764 16.500 3.079 0.961 0.634 24 | 36 0.839 13.544 1.543 0.787 0.899 25 | 37 0.000 67.437 47.941 0.000 0.000 26 | 39 0.525 17.456 2.583 0.657 0.438 27 | 40 0.250 54.246 11.347 0.991 0.143 28 | 41 0.117 43.359 11.745 0.988 0.062 29 | 42 0.607 23.923 2.714 0.881 0.462 30 | 43 0.814 12.864 2.155 0.909 0.737 31 | 44 0.099 28.546 5.346 1.000 0.052 32 | 45 0.518 19.038 3.769 0.713 0.407 33 | DM average 0.561342422319 +/- 0.233260755632 (Median: 0.61615532753) 34 | HD average 27.8680678934 +/- 13.849850917 (Median: 23.9408895565) 35 | ASSD average 5.95452813413 +/- 8.56704426709 (Median: 3.07765457275) 36 | Prec. average 0.780962725387 +/- 0.239731971234 (Median: 0.881594165477) 37 | Rec. average 0.512306391073 +/- 0.253186259643 (Median: 0.541430673183) 38 | INFO: Evaluating in sequence space.. 39 | Metrics: 40 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 41 | 03 0.705 34.598 5.621 0.974 0.553 42 | 05 0.503 29.850 9.003 0.999 0.336 43 | 07 0.883 13.077 1.770 0.952 0.823 44 | 09 0.420 15.297 3.388 0.944 0.270 45 | 10 0.395 42.532 8.736 0.976 0.247 46 | 11 0.715 25.807 2.691 0.933 0.579 47 | 12 0.638 31.464 5.497 0.986 0.471 48 | 13 0.849 24.920 2.467 0.895 0.808 49 | 15 0.825 11.225 1.975 0.807 0.843 50 | 17 0.534 60.374 7.982 0.985 0.366 51 | 18 0.802 18.248 2.148 0.946 0.696 52 | 22 0.374 25.807 6.350 0.262 0.657 53 | 23 0.660 15.297 2.800 0.623 0.702 54 | 25 0.619 25.807 3.612 0.515 0.776 55 | 26 0.642 22.045 3.856 0.514 0.854 56 | 32 0.726 18.248 3.205 0.721 0.731 57 | 33 0.751 21.000 3.146 0.686 0.829 58 | 34 0.763 33.675 4.144 0.720 0.812 59 | 35 0.786 15.297 3.141 0.964 0.664 60 | 36 0.836 12.369 2.339 0.776 0.907 61 | 37 0.000 66.948 48.706 0.000 0.000 62 | 39 0.634 16.155 2.547 0.755 0.547 63 | 40 0.255 54.415 11.125 0.974 0.146 64 | 41 0.127 44.091 11.671 0.996 0.068 65 | 42 0.630 21.840 3.180 0.904 0.483 66 | 43 0.826 15.297 2.631 0.922 0.748 67 | 44 0.138 26.325 6.094 1.000 0.074 68 | 45 0.643 16.432 3.054 0.858 0.514 69 | DM average 0.595617291757 +/- 0.233859099678 (Median: 0.642409331406) 70 | HD average 27.0871675837 +/- 14.4023681884 (Median: 23.4826396369) 71 | ASSD average 6.17430480698 +/- 8.62509025762 (Median: 3.29676250469) 72 | Prec. average 0.806647244853 +/- 0.237357914509 (Median: 0.912898671096) 73 | Rec. average 0.553723256739 +/- 0.265355356007 (Median: 0.618110117817) 74 | -------------------------------------------------------------------------------- /scripts/apply_rdf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | """ 4 | Apply an RDF to a case. 5 | arg1: the decision forest file 6 | arg2: the case folder holding the feature files 7 | arg3: the cases mask file 8 | arg4: file containing a struct identifying the features to use 9 | arg5: the target segmentation file 10 | arg6: the target probability file 11 | """ 12 | 13 | import os 14 | import sys 15 | import imp 16 | import pickle 17 | import numpy 18 | 19 | from scipy.ndimage.morphology import binary_fill_holes, binary_dilation 20 | from scipy.ndimage.measurements import label 21 | 22 | from medpy.io import load, save 23 | from medpy.features.utilities import join 24 | 25 | # constants 26 | n_jobs = 6 27 | probability_threshold = 0.5 28 | 29 | def main(): 30 | # catch parameters 31 | forest_file = sys.argv[1] 32 | case_folder = sys.argv[2] 33 | mask_file = sys.argv[3] 34 | feature_cnf_file = sys.argv[4] 35 | segmentation_file = sys.argv[5] 36 | probability_file = sys.argv[6] 37 | 38 | # load features to use and create proper names from them 39 | features_to_use = load_feature_names(feature_cnf_file) 40 | 41 | # loading case features 42 | feature_vector = [] 43 | 44 | for feature_name in features_to_use: 45 | _file = os.path.join(case_folder, '{}.npy'.format(feature_name)) 46 | if not os.path.isfile(_file): 47 | raise Exception('The feature "{}" could not be found in folder "{}". Breaking.'.format(feature_name, case_folder)) 48 | with open(_file, 'r') as f: 49 | feature_vector.append(numpy.load(f)) 50 | feature_vector = join(*feature_vector) 51 | if 1 == feature_vector.ndim: 52 | feature_vector = numpy.expand_dims(feature_vector, -1) 53 | 54 | # load and apply the decision forest 55 | with open(forest_file, 'r') as f: 56 | forest = pickle.load(f) 57 | probability_results = forest.predict_proba(feature_vector)[:,1] 58 | classification_results = probability_results > probability_threshold # equivalent to forest.predict 59 | 60 | # preparing image 61 | m, h = load(mask_file) 62 | m = m.astype(numpy.bool) 63 | oc = numpy.zeros(m.shape, numpy.uint8) 64 | op = numpy.zeros(m.shape, numpy.float32) 65 | oc[m] = numpy.squeeze(classification_results).ravel() 66 | op[m] = numpy.squeeze(probability_results).ravel() 67 | 68 | # applying the post-processing morphology 69 | oc = binary_fill_holes(oc) 70 | 71 | # saving the results 72 | save(oc, segmentation_file, h, True) 73 | save(op, probability_file, h, True) 74 | 75 | def feature_struct_entry_to_name(fstruct): 76 | seq, fcall, fargs, _ = fstruct 77 | return 'feature.{}.{}.{}'.format(seq, fcall.func_name, '_'.join(['arg{}'.format(i) for i in fargs])) 78 | 79 | def load_feature_struct(f): 80 | "Load the feature struct from a feature config file." 81 | d, m = os.path.split(os.path.splitext(f)[0]) 82 | f, filename, desc = imp.find_module(m, [d]) 83 | return imp.load_module(m, f, filename, desc).features_to_extract 84 | 85 | def load_feature_names(f): 86 | "Load the feature names from a feature config file." 87 | fs = load_feature_struct(f) 88 | return [feature_struct_entry_to_name(e) for e in fs] 89 | 90 | if __name__ == "__main__": 91 | main() 92 | -------------------------------------------------------------------------------- /logs/exp00.b.log: -------------------------------------------------------------------------------- 1 | INFO: Reverting segmentations.... 2 | INFO: Evaluating in original space... 3 | Metrics: 4 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 5 | 03 0.613 34.204 6.716 0.986 0.445 6 | 05 0.496 28.982 9.102 0.999 0.330 7 | 07 0.849 13.755 1.695 0.938 0.776 8 | 09 0.397 17.285 2.894 0.842 0.260 9 | 10 0.371 42.639 8.609 0.936 0.232 10 | 11 0.630 28.126 2.993 0.885 0.489 11 | 12 0.720 24.500 4.033 0.910 0.595 12 | 13 0.795 23.959 2.790 0.897 0.714 13 | 15 0.717 17.850 2.387 0.717 0.718 14 | 17 0.452 60.682 7.837 0.979 0.294 15 | 18 0.727 17.101 2.165 0.943 0.592 16 | 22 0.319 23.964 6.334 0.217 0.597 17 | 23 0.665 15.643 2.059 0.642 0.689 18 | 25 0.611 27.251 2.848 0.482 0.832 19 | 26 0.620 21.918 2.858 0.525 0.757 20 | 31 0.628 21.542 2.615 0.795 0.519 21 | 32 0.644 37.673 4.456 0.595 0.702 22 | 33 0.724 17.101 2.718 0.718 0.729 23 | 34 0.643 36.356 5.257 0.591 0.704 24 | 35 0.778 16.622 2.802 0.948 0.659 25 | 36 0.838 12.103 1.626 0.770 0.919 26 | 37 0.000 58.377 44.931 0.000 0.000 27 | 39 0.557 17.105 2.369 0.711 0.457 28 | 40 0.215 52.553 11.353 0.987 0.121 29 | 41 0.007 53.495 14.914 0.898 0.003 30 | 42 0.622 23.948 2.503 0.885 0.479 31 | 43 0.783 14.375 2.619 0.907 0.689 32 | 44 0.027 31.987 7.443 1.000 0.014 33 | 45 0.483 21.323 5.206 0.518 0.452 34 | DM average 0.549307196579 +/- 0.236879602714 (Median: 0.621673003802) 35 | HD average 28.0144458487 +/- 13.5944418748 (Median: 23.9590353645) 36 | ASSD average 6.07348220366 +/- 7.99259797079 (Median: 2.89367929614) 37 | Prec. average 0.766337361862 +/- 0.238968462132 (Median: 0.885039583192) 38 | Rec. average 0.509241849857 +/- 0.253567177823 (Median: 0.591836234971) 39 | INFO: Evaluating in sequence space.. 40 | Metrics: 41 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 42 | 03 0.624 36.125 6.936 0.979 0.458 43 | 05 0.508 31.321 8.977 0.998 0.341 44 | 07 0.883 14.697 1.788 0.945 0.828 45 | 09 0.463 16.155 3.303 0.898 0.312 46 | 10 0.396 41.893 8.838 0.977 0.248 47 | 11 0.672 28.618 3.275 0.927 0.527 48 | 12 0.778 23.622 3.327 0.972 0.648 49 | 13 0.828 24.920 2.697 0.905 0.763 50 | 15 0.816 12.728 2.039 0.796 0.836 51 | 17 0.468 62.714 8.762 0.987 0.307 52 | 18 0.769 18.974 2.402 0.970 0.638 53 | 22 0.403 23.431 5.755 0.275 0.757 54 | 23 0.682 15.297 2.532 0.645 0.723 55 | 25 0.597 21.424 3.715 0.466 0.832 56 | 26 0.681 21.840 3.330 0.563 0.861 57 | 31 0.693 17.493 2.720 0.856 0.582 58 | 32 0.674 36.620 4.946 0.604 0.762 59 | 33 0.749 15.297 2.978 0.727 0.774 60 | 34 0.706 36.125 5.131 0.632 0.801 61 | 35 0.800 15.588 2.960 0.950 0.691 62 | 36 0.829 12.369 2.498 0.757 0.918 63 | 37 0.000 57.784 45.908 0.000 0.000 64 | 39 0.656 15.297 2.316 0.795 0.559 65 | 40 0.220 53.245 11.369 0.969 0.124 66 | 41 0.011 53.160 15.376 0.958 0.005 67 | 42 0.636 22.450 3.095 0.901 0.492 68 | 43 0.800 18.000 2.959 0.920 0.707 69 | 44 0.067 25.100 6.530 1.000 0.034 70 | 45 0.601 18.974 4.214 0.633 0.571 71 | DM average 0.586589632906 +/- 0.241973504031 (Median: 0.672336978534) 72 | HD average 27.2848315815 +/- 14.0621784272 (Median: 22.4499443206) 73 | ASSD average 6.2302374546 +/- 8.12586745198 (Median: 3.32697209233) 74 | Prec. average 0.793270625245 +/- 0.235309109629 (Median: 0.90081300813) 75 | Rec. average 0.555189157731 +/- 0.270310663094 (Median: 0.637592137592) 76 | -------------------------------------------------------------------------------- /documentation/cmtk_tools: -------------------------------------------------------------------------------- 1 | List of interesting CMTK tools 2 | ############################## 3 | 4 | mrbias 5 | This program corrects intensity inhomogeneity artifacts in MR images using a bias field estimated via entropy minimization. 6 | sympl 7 | Compute the approximate symmetry plane of an image to determine, for example, the mid-sagittal plane in human brain images. Various forms of output are supported, e.g., writing the input image 8 | with the symmetry plane drawn into it, or the input image realigned along the symmetry plane. 9 | 10 | 11 | 12 | concat_affine 13 | This tool computes the explicit concatenation of multiple affine coordinate transformations, each of which can be optionally inverted. 14 | convertx 15 | This tool converts between image file formats and pixel data types. It can also apply simple, general-purpose image operations in the process. An arbitrary number of operations can be specified 16 | on the command line, which will be applied exactly in the order given. 17 | describe 18 | This tool prints a detailed description of the input image(s) 19 | detect_spheres_matched_filter 20 | This tool detects spherical objects in three-dimensional images. 21 | fit_affine_dfield 22 | Fit a linear affine transformation to a nonrigid transformation, either a B-spline free-form deformation or a non-parametric deformation field. 23 | 24 | fit_affine_xform 25 | Fit a linear affine transformation to a list of concatenated, optionally inverted, transformations. 26 | glm 27 | Statistical modeling of pixel intensities in multiple images using a General Linear Model. 28 | gmm 29 | Segment an image into c classes using the EM algorithm for Gaussian mixtures with optional priors. 30 | hausdorff 31 | This tool computes the Hausdorff distance between two label images. 32 | mrbias 33 | This program corrects intensity inhomogeneity artifacts in MR images using a bias field estimated via entropy minimization. 34 | overlap 35 | Compute overlap measures between two or more images 36 | reorient 37 | Convert between image orientations, i.e., physically re-order pixel array and adapt stored anatomical orientation information 38 | sympl 39 | Compute the approximate symmetry plane of an image to determine, for example, the mid-sagittal plane in human brain images. Various forms of output are supported, e.g., writing the input image 40 | with the symmetry plane drawn into it, or the input image realigned along the symmetry plane. 41 | symplx 42 | Compute the approximate symmetry plane of an image to determine, for example, the mid-sagittal plane in human brain images. Various forms of output are supported, e.g., writing the input image 43 | with the symmetry plane drawn into it, or the input image realigned along the symmetry plane. 44 | warp 45 | This program performs nonrigid image registration using multi-resolution optimization of voxel-based image similarity measures and a multi-resolution B-spline transformation model. 46 | warp2ps 47 | Write deformation field as deformed grid in PostScript format for visualization and illustration 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /experiments/RemarksOnWorstCases: -------------------------------------------------------------------------------- 1 | Conclusions 2 | ########### 3 | - Ground truth of case 22 invalid, remove the case. 4 | - The tendency of the segmentation to keep distance from dark areas becomes a problem where 5 | a) the lesion reaches near the ventricle 6 | b) the lesion reaches near the brain border (strangely) 7 | c) there are haemorrhages present inside the ischemic stroke lesion 8 | => I must find a way to enable the classifier to differ between the good and bad cases. 9 | - Large, inhomogeneous lesions seem to pose a problem, especially when they are additionally only slightly hyperintensive. This might be caused by a failure of the intensity standardization. 10 | => Perform standardization in standard space under exclusion of the previously segmented lesion areas. 11 | => Note that using intensity standardization zero-mean / unit-variance did not improve these cases. 12 | - False positive segmentation in cerebellum in an area of only very slight hyperintensity. No idea what might have caused this. 13 | => After registration to std space, this might be possible to overcome due to the centerdistance feature. Otherwise, I might have to think of another feature. 14 | - False positive segmentation in skull. 15 | => After registration to std space, this might be possible to overcome due to the centerdistance feature and the improved skull-stripping. 16 | - Very small lesion seem to pose a real challenge. Maybe these would require a less strong sub-sampling? 17 | => No idea how to solve this. 18 | 19 | 20 | Analysis 21 | ######## 22 | 23 | 24 | 25 | 05 0.370 32.120 10.904 26 | large, inomogeneous and diffuse lesion; strong under-segmentation; might be caused by a fail of intenstity standardization 27 | 28 | 10 0.480 27.873 7.593 29 | large, inomogeneous and diffuse lesion; additionally two haemorrhages, which the segmentation avoids; strong under-segmentation; ground truth potentially to big; hold too much distance to brain border 30 | 31 | 11 0.505 41.759 5.610 32 | small, unconnected embolic parts which are missed; segmentation tries to stay away from ventricles; already before post-processing the embolic parts were missed 33 | 34 | 22 0.192 26.324 7.906 35 | very small lesions with large, adjacent WML that got include in the segmentation 36 | !!! Looking at the DW, one can see that the segmented WML is actually part of the lesion and wrongly not included in the ground truth !!! 37 | 38 | 23 0.488 95.868 13.875 39 | small lesion; but main problem is false positive in cerebellum; a segmentation in std space might help to remove this due to centerdistance feature 40 | 41 | 37 0.000 62.795 40.789 42 | very small lesion with very large amount of other WMLs; just a very difficult case 43 | 44 | 40 0.382 44.311 8.292 45 | large, diffuse and only partially connected lesion; strong under-segmentation; might be caused by a fail of intenstity standardization 46 | 47 | 41 0.145 50.769 11.584 48 | large, diffuse and only slightly hyperintense; strong under-segmentation; might be caused by a fail of intenstity standardization 49 | 50 | 42 0.466 64.157 11.959 51 | lesion itself sufficiently found; larger false positive in upper skull 52 | 53 | 44 0.000 inf inf 54 | very small and only slightly hyperintense lesion; just very difficult 55 | 56 | 45 0.329 32.797 9.251 57 | partially WML included; under-segmented 58 | 59 | 60 | -------------------------------------------------------------------------------- /scripts/sample_trainingset.alternative.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | """ 4 | Sample a traning set for a case by drawing from all other images using stratified random sampling. 5 | 6 | arg1: directory with case-folders containing feature files 7 | arg2: directory containing segmentations 8 | arg3: directory containing brain masks 9 | arg4: target directory 10 | arg5: file containing a struct identifying the features to sample 11 | arg6: number of samples to draw OR a file which contains a set of indices identifying the samples to draw 12 | arg7+: indices of all cases from which to draw the training sample 13 | """ 14 | 15 | import os 16 | import sys 17 | import imp 18 | import numpy 19 | import itertools 20 | 21 | from medpy.io import load 22 | from medpy.features.utilities import append, join 23 | from sklearn.cross_validation import StratifiedShuffleSplit 24 | 25 | # main settings 26 | min_no_of_samples_per_class_and_case = 4 27 | 28 | # debug settings 29 | verboose = False 30 | debug = False 31 | override = False # activate override (will signal a warning) 32 | 33 | # constants 34 | trainingset_features_file = 'trainingset.features.npy' 35 | trainingset_classes_file = 'trainingset.classes.npy' 36 | trainingset_feature_names_file = 'trainingset.fnames.npy' 37 | trainingset_sample_indices_file = 'trainingset.indices.npy' 38 | trainingset_suffix = 'npy' 39 | 40 | def main(): 41 | # catch arguments 42 | src_dir = sys.argv[1] 43 | seg_dir = sys.argv[2] 44 | msk_dir = sys.argv[3] 45 | trg_dir = sys.argv[4] 46 | feature_cnf_file = sys.argv[5] 47 | n_samples = int(sys.argv[6]) 48 | cases = sys.argv[7:] 49 | 50 | # load features to use and create proper names from them 51 | features_to_use = load_feature_names(feature_cnf_file) 52 | 53 | # warn if target sample set already exists 54 | if os.path.isfile('{}/{}.{}'.format(trg_dir, trainingset_features_file, trainingset_suffix)) or 55 | os.path.isfile('{}/{}.{}'.format(trg_dir, trainingset_classes_file, trainingset_suffix)) or 56 | os.path.isfile('{}/{}.{}'.format(trg_dir, trainingset_feature_names_file, trainingset_suffix)) or 57 | os.path.isfile('{}/{}.{}'.format(trg_dir, trainingset_sample_indices_file, trainingset_suffix)): 58 | if override: 59 | print 'WARNING: The target directory {}/ already contains at least on of the files to create. Replacing.'.format(trg_dir) 60 | else: 61 | print 'WARNING: The target directory {}/ already contains at least on of the files to create. Skipping.'.format(trg_dir) 62 | sys.exit(1) 63 | 64 | # initializing collections 65 | training_set_selections = dict.fromkeys(training_set_cases) 66 | 67 | # iterate over cases, load their respective samples and perform a sampling for each 68 | 69 | 70 | # draw random stratified sample and extract training set indices 71 | sss = StratifiedShuffleSplit(classes, n_iter=1, train_size=n_samples) 72 | sample_indices, _ = sss.next() 73 | 74 | # save 75 | 76 | def load_feature_struct(f): 77 | "Load the feature struct from a feature config file." 78 | d, m = os.path.split(os.path.splitext(f)[0]) 79 | f, filename, desc = imp.find_module(m, [d]) 80 | return imp.load_module(m, f, filename, desc).features_to_extract 81 | 82 | def load_feature_names(f): 83 | "Load the feature names from a feature config file." 84 | fs = load_feature_struct(f) 85 | return [feature_struct_entry_to_name(e) for e in fs] 86 | 87 | if __name__ == "__main__": 88 | main() 89 | 90 | 91 | -------------------------------------------------------------------------------- /logs/exp00.f.log: -------------------------------------------------------------------------------- 1 | INFO: Reverting segmentations.... 2 | INFO: Evaluating in original space... 3 | Metrics: 4 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 5 | 03 0.728 33.498 4.923 0.975 0.581 6 | 05 0.418 32.019 10.422 1.000 0.264 7 | 06 0.736 20.635 2.942 0.970 0.592 8 | 07 0.835 24.276 2.663 0.864 0.808 9 | 09 0.615 12.087 1.614 0.753 0.520 10 | 10 0.543 27.592 6.785 0.952 0.380 11 | 11 0.613 23.851 2.583 0.931 0.456 12 | 12 0.691 24.652 4.234 0.921 0.553 13 | 13 0.801 23.620 2.506 0.835 0.770 14 | 15 0.737 19.963 2.233 0.741 0.733 15 | 17 0.765 52.288 4.712 0.761 0.769 16 | 18 0.755 16.821 2.017 0.962 0.622 17 | 19 0.000 inf inf 0.000 0.000 18 | 20 0.792 9.444 1.326 0.886 0.716 19 | 21 0.779 17.759 2.205 0.942 0.663 20 | 22 0.175 36.099 9.577 0.136 0.246 21 | 23 0.552 36.011 5.085 0.550 0.555 22 | 25 0.600 33.254 3.499 0.536 0.680 23 | 26 0.601 20.153 3.221 0.475 0.819 24 | 29 0.673 42.197 4.082 0.788 0.587 25 | 30 0.683 18.953 3.892 0.942 0.536 26 | 32 0.618 28.212 3.375 0.829 0.492 27 | 33 0.641 74.418 9.913 0.612 0.673 28 | 34 0.734 12.625 1.727 0.814 0.669 29 | 35 0.748 15.509 3.235 0.969 0.610 30 | 36 0.828 19.504 1.392 0.867 0.791 31 | 37 0.000 68.418 42.405 0.000 0.000 32 | 39 0.545 17.082 2.424 0.728 0.435 33 | 40 0.429 50.188 8.992 0.992 0.274 34 | 41 0.122 46.694 11.271 0.984 0.065 35 | 42 0.514 24.065 3.393 0.876 0.364 36 | 43 0.849 12.514 1.620 0.885 0.816 37 | 44 0.104 27.772 6.320 0.983 0.055 38 | 45 0.275 22.461 6.058 0.692 0.172 39 | WARNING: Average values only computed on 33 of 34 cases! 40 | DM average 0.59085857849 +/- 0.223083003523 (Median: 0.641201012243) 41 | HD average 28.6252356527 +/- 15.2091373152 (Median: 24.0653103067) 42 | ASSD average 5.53476476348 +/- 7.08157741337 (Median: 3.39290310984) 43 | Prec. average 0.792490251694 +/- 0.230993246531 (Median: 0.867411545624) 44 | Rec. average 0.523160648322 +/- 0.229612091181 (Median: 0.580517642392) 45 | INFO: Evaluating in sequence space.. 46 | Metrics: 47 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 48 | 03 0.741 34.337 4.969 0.973 0.599 49 | 05 0.430 33.941 10.290 0.999 0.274 50 | 06 0.759 22.650 3.554 0.988 0.616 51 | 07 0.857 26.833 2.547 0.862 0.852 52 | 09 0.684 9.950 2.103 0.792 0.601 53 | 10 0.567 28.618 6.278 0.981 0.399 54 | 11 0.648 20.125 3.078 0.970 0.487 55 | 12 0.741 26.325 3.929 0.976 0.597 56 | 13 0.828 23.622 2.852 0.840 0.815 57 | 15 0.811 15.297 2.139 0.796 0.827 58 | 17 0.764 53.498 5.431 0.747 0.781 59 | 18 0.775 19.209 2.435 0.952 0.654 60 | 19 0.000 inf inf 0.000 0.000 61 | 20 0.861 9.950 1.487 0.954 0.784 62 | 21 0.794 17.234 2.687 0.935 0.690 63 | 22 0.252 34.337 8.886 0.196 0.355 64 | 23 0.569 36.742 5.219 0.549 0.590 65 | 25 0.615 28.618 4.184 0.539 0.715 66 | 26 0.642 19.672 3.814 0.498 0.902 67 | 29 0.714 42.532 4.192 0.832 0.626 68 | 30 0.709 21.424 4.322 0.972 0.558 69 | 32 0.656 24.187 3.783 0.855 0.532 70 | 33 0.660 75.060 11.143 0.619 0.707 71 | 34 0.792 13.077 1.960 0.861 0.733 72 | 35 0.771 13.748 3.326 0.972 0.638 73 | 36 0.863 17.748 1.791 0.895 0.832 74 | 37 0.000 69.584 43.083 0.000 0.000 75 | 39 0.606 15.297 2.528 0.802 0.486 76 | 40 0.431 50.289 8.770 0.984 0.276 77 | 41 0.132 46.184 11.586 0.997 0.071 78 | 42 0.543 22.450 3.815 0.918 0.385 79 | 43 0.850 15.297 2.321 0.881 0.822 80 | 44 0.155 25.100 6.286 1.000 0.084 81 | 45 0.336 21.000 5.592 0.803 0.213 82 | WARNING: Average values only computed on 33 of 34 cases! 83 | DM average 0.622806496042 +/- 0.223199114283 (Median: 0.683729433272) 84 | HD average 28.3010489599 +/- 15.5813317946 (Median: 23.622023622) 85 | ASSD average 5.76922571815 +/- 7.12058002497 (Median: 3.81534948094) 86 | Prec. average 0.816279709785 +/- 0.229030034043 (Median: 0.88085634502) 87 | Rec. average 0.560574397708 +/- 0.238266780021 (Median: 0.601286173633) 88 | -------------------------------------------------------------------------------- /logs/exp01.b.thr1000.log: -------------------------------------------------------------------------------- 1 | INFO: Reverting segmentations.... 2 | INFO: Evaluating in original space... 3 | Metrics: 4 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 5 | 03 0.612 33.110 6.774 0.977 0.445 6 | 04 0.713 16.472 2.558 0.709 0.717 7 | 05 0.370 32.120 10.904 1.000 0.227 8 | 06 0.785 19.473 2.514 0.894 0.700 9 | 07 0.868 12.537 1.503 0.924 0.819 10 | 08 0.688 26.906 6.040 0.945 0.541 11 | 09 0.594 23.223 2.781 0.575 0.615 12 | 10 0.480 27.873 7.593 0.945 0.322 13 | 11 0.505 41.759 5.610 0.911 0.350 14 | 12 0.778 20.864 2.869 0.912 0.678 15 | 13 0.777 23.620 3.010 0.837 0.725 16 | 15 0.688 19.963 2.740 0.717 0.661 17 | 17 0.774 15.496 2.804 0.722 0.834 18 | 18 0.745 16.524 2.114 0.921 0.626 19 | 19 0.604 18.972 3.089 0.611 0.597 20 | 20 0.793 8.582 1.327 0.842 0.750 21 | 21 0.807 16.886 1.676 0.940 0.707 22 | 22 0.192 26.324 7.906 0.148 0.271 23 | 23 0.503 95.868 12.358 0.450 0.568 24 | 25 0.582 27.225 3.146 0.480 0.739 25 | 26 0.637 19.146 2.833 0.516 0.834 26 | 28 0.784 24.482 2.453 0.782 0.787 27 | 29 0.713 42.197 3.706 0.804 0.641 28 | 30 0.595 18.899 4.883 0.927 0.438 29 | 31 0.572 21.459 3.310 0.825 0.438 30 | 32 0.570 69.302 7.727 0.569 0.572 31 | 33 0.670 21.356 2.639 0.936 0.522 32 | 34 0.730 11.627 1.968 0.742 0.718 33 | 35 0.807 16.549 2.577 0.956 0.698 34 | 36 0.841 16.566 1.330 0.818 0.865 35 | 37 0.000 56.063 45.213 0.000 0.000 36 | 39 0.616 15.636 1.771 0.641 0.593 37 | 40 0.382 44.311 8.292 0.985 0.237 38 | 41 0.145 50.769 11.584 0.956 0.078 39 | 42 0.466 64.157 11.959 0.558 0.400 40 | 43 0.710 16.234 3.407 0.934 0.573 41 | 44 0.000 inf inf 0.000 0.000 42 | 45 0.329 32.797 9.251 0.330 0.328 43 | WARNING: Average values only computed on 37 of 38 cases! 44 | DM average 0.606181833433 +/- 0.199407611214 45 | HD average 28.7932142867 +/- 18.1463539737 46 | ASSD average 5.78971754656 +/- 7.31787755933 47 | Prec. average 0.749731730119 +/- 0.237179545305 48 | Rec. average 0.557159681452 +/- 0.212883344243 49 | INFO: Evaluating in sequence space.. 50 | Metrics: 51 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 52 | 03 0.622 35.369 6.969 0.973 0.457 53 | 04 0.771 15.000 2.548 0.747 0.797 54 | 05 0.382 33.941 10.621 0.998 0.236 55 | 06 0.814 19.900 2.872 0.914 0.733 56 | 07 0.878 11.225 1.954 0.908 0.850 57 | 08 0.716 25.981 5.210 0.978 0.565 58 | 09 0.619 22.650 3.633 0.572 0.675 59 | 10 0.506 30.150 7.229 0.983 0.340 60 | 11 0.538 43.784 6.218 0.959 0.374 61 | 12 0.832 22.045 2.540 0.967 0.730 62 | 13 0.811 23.622 2.968 0.846 0.779 63 | 15 0.801 15.297 2.185 0.816 0.787 64 | 17 0.780 16.155 3.292 0.717 0.855 65 | 18 0.791 15.588 2.242 0.942 0.681 66 | 19 0.634 18.493 3.492 0.629 0.639 67 | 20 0.890 8.485 1.250 0.933 0.851 68 | 21 0.821 16.155 2.288 0.932 0.733 69 | 22 0.276 23.043 7.175 0.212 0.396 70 | 23 0.491 98.362 14.225 0.431 0.570 71 | 25 0.608 23.431 3.636 0.493 0.792 72 | 26 0.674 18.493 3.391 0.537 0.905 73 | 28 0.832 27.659 2.628 0.822 0.842 74 | 29 0.751 42.532 3.857 0.847 0.675 75 | 30 0.628 19.209 5.137 0.965 0.466 76 | 31 0.609 20.125 3.457 0.853 0.473 77 | 32 0.608 66.880 8.212 0.587 0.630 78 | 33 0.685 17.748 3.304 0.935 0.540 79 | 34 0.818 11.225 1.780 0.816 0.820 80 | 35 0.825 15.588 2.625 0.957 0.726 81 | 36 0.854 15.000 2.066 0.819 0.891 82 | 37 0.000 55.399 45.664 0.000 0.000 83 | 39 0.710 12.728 1.954 0.730 0.691 84 | 40 0.386 45.200 8.213 0.970 0.241 85 | 41 0.153 52.048 12.124 0.956 0.083 86 | 42 0.481 66.476 12.687 0.562 0.420 87 | 43 0.734 17.748 3.718 0.953 0.596 88 | 44 0.000 inf inf 0.000 0.000 89 | 45 0.418 30.150 7.802 0.405 0.433 90 | WARNING: Average values only computed on 37 of 38 cases! 91 | DM average 0.641783460688 +/- 0.205085836628 92 | HD average 28.4563479645 +/- 18.8254727081 93 | ASSD average 5.97749153674 +/- 7.37882697412 94 | Prec. average 0.774776366391 +/- 0.23473302884 95 | Rec. average 0.601933498874 +/- 0.225578959238 96 | -------------------------------------------------------------------------------- /logs/exp01.b.thr2000.log: -------------------------------------------------------------------------------- 1 | INFO: Reverting segmentations.... 2 | INFO: Evaluating in original space... 3 | Metrics: 4 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 5 | 03 0.612 33.110 6.774 0.977 0.445 6 | 04 0.713 16.472 2.558 0.709 0.717 7 | 05 0.370 32.120 10.904 1.000 0.227 8 | 06 0.785 19.473 2.514 0.894 0.700 9 | 07 0.868 12.537 1.503 0.924 0.819 10 | 08 0.688 26.906 6.040 0.945 0.541 11 | 09 0.632 11.557 1.671 0.651 0.615 12 | 10 0.480 27.873 7.593 0.945 0.322 13 | 11 0.505 41.759 5.610 0.911 0.350 14 | 12 0.778 20.864 2.869 0.912 0.678 15 | 13 0.777 23.620 3.010 0.837 0.725 16 | 15 0.688 19.963 2.740 0.717 0.661 17 | 17 0.766 49.635 4.643 0.719 0.819 18 | 18 0.745 16.524 2.114 0.921 0.626 19 | 19 0.604 18.972 3.089 0.611 0.597 20 | 20 0.793 8.582 1.327 0.842 0.750 21 | 21 0.807 16.886 1.676 0.940 0.707 22 | 22 0.192 26.324 7.906 0.148 0.271 23 | 23 0.488 95.868 13.875 0.442 0.544 24 | 25 0.582 27.225 3.146 0.480 0.739 25 | 26 0.637 19.146 2.833 0.516 0.834 26 | 28 0.784 24.482 2.453 0.782 0.787 27 | 29 0.713 42.197 3.706 0.804 0.641 28 | 30 0.595 18.899 4.883 0.927 0.438 29 | 31 0.572 21.459 3.310 0.825 0.438 30 | 32 0.576 64.755 6.746 0.580 0.572 31 | 33 0.670 21.356 2.639 0.936 0.522 32 | 34 0.730 11.627 1.968 0.742 0.718 33 | 35 0.807 16.549 2.577 0.956 0.698 34 | 36 0.841 16.566 1.330 0.818 0.865 35 | 37 0.000 62.795 40.789 0.000 0.000 36 | 39 0.616 15.636 1.771 0.641 0.593 37 | 40 0.382 44.311 8.292 0.985 0.237 38 | 41 0.145 50.769 11.584 0.956 0.078 39 | 42 0.466 64.157 11.959 0.558 0.400 40 | 43 0.710 16.234 3.407 0.934 0.573 41 | 44 0.000 inf inf 0.000 0.000 42 | 45 0.329 32.797 9.251 0.330 0.328 43 | WARNING: Average values only computed on 37 of 38 cases! 44 | DM average 0.606759157315 +/- 0.19946078888 45 | HD average 29.4596848145 +/- 18.5674305036 46 | ASSD average 5.70433740263 +/- 6.7214456748 47 | Prec. average 0.751803173974 +/- 0.236040024401 48 | Rec. average 0.556110325845 +/- 0.212389676207 49 | INFO: Evaluating in sequence space.. 50 | Metrics: 51 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 52 | 03 0.622 35.369 6.969 0.973 0.457 53 | 04 0.771 15.000 2.548 0.747 0.797 54 | 05 0.382 33.941 10.621 0.998 0.236 55 | 06 0.814 19.900 2.872 0.914 0.733 56 | 07 0.878 11.225 1.954 0.908 0.850 57 | 08 0.716 25.981 5.210 0.978 0.565 58 | 09 0.673 12.369 2.289 0.671 0.675 59 | 10 0.506 30.150 7.229 0.983 0.340 60 | 11 0.538 43.784 6.218 0.959 0.374 61 | 12 0.832 22.045 2.540 0.967 0.730 62 | 13 0.811 23.622 2.968 0.846 0.779 63 | 15 0.801 15.297 2.185 0.816 0.787 64 | 17 0.772 51.439 5.266 0.714 0.839 65 | 18 0.791 15.588 2.242 0.942 0.681 66 | 19 0.634 18.493 3.492 0.629 0.639 67 | 20 0.890 8.485 1.250 0.933 0.851 68 | 21 0.821 16.155 2.288 0.932 0.733 69 | 22 0.276 23.043 7.175 0.212 0.396 70 | 23 0.469 98.362 15.787 0.418 0.535 71 | 25 0.608 23.431 3.636 0.493 0.792 72 | 26 0.674 18.493 3.391 0.537 0.905 73 | 28 0.832 27.659 2.628 0.822 0.842 74 | 29 0.751 42.532 3.857 0.847 0.675 75 | 30 0.628 19.209 5.137 0.965 0.466 76 | 31 0.609 20.125 3.457 0.853 0.473 77 | 32 0.616 62.642 6.728 0.602 0.630 78 | 33 0.685 17.748 3.304 0.935 0.540 79 | 34 0.818 11.225 1.780 0.816 0.820 80 | 35 0.825 15.588 2.625 0.957 0.726 81 | 36 0.854 15.000 2.066 0.819 0.891 82 | 37 0.000 67.683 41.449 0.000 0.000 83 | 39 0.710 12.728 1.954 0.730 0.691 84 | 40 0.386 45.200 8.213 0.970 0.241 85 | 41 0.153 52.048 12.124 0.956 0.083 86 | 42 0.481 66.476 12.687 0.562 0.420 87 | 43 0.734 17.748 3.718 0.953 0.596 88 | 44 0.000 inf inf 0.000 0.000 89 | 45 0.418 30.150 7.802 0.405 0.433 90 | WARNING: Average values only computed on 37 of 38 cases! 91 | DM average 0.642630114808 +/- 0.205401877578 92 | HD average 29.3495771935 +/- 19.5836982586 93 | ASSD average 5.88267809435 +/- 6.82331743633 94 | Prec. average 0.777401492113 +/- 0.233224702384 95 | Rec. average 0.600566302365 +/- 0.225327469844 96 | -------------------------------------------------------------------------------- /logs/exp01.b.thr250.log: -------------------------------------------------------------------------------- 1 | INFO: Reverting segmentations.... 2 | INFO: Evaluating in original space... 3 | Metrics: 4 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 5 | 03 0.612 33.110 6.774 0.977 0.445 6 | 04 0.706 62.907 3.831 0.696 0.717 7 | 05 0.370 32.120 10.904 1.000 0.227 8 | 06 0.785 19.473 2.514 0.894 0.700 9 | 07 0.868 12.537 1.503 0.924 0.819 10 | 08 0.688 26.906 6.040 0.945 0.541 11 | 09 0.569 71.792 6.021 0.529 0.615 12 | 10 0.480 27.873 7.593 0.945 0.322 13 | 11 0.519 31.149 4.360 0.914 0.362 14 | 12 0.778 20.864 2.869 0.912 0.678 15 | 13 0.777 23.620 3.010 0.837 0.725 16 | 15 0.688 19.963 2.740 0.717 0.661 17 | 17 0.774 15.496 2.804 0.722 0.834 18 | 18 0.745 16.524 2.114 0.921 0.626 19 | 19 0.604 18.972 3.089 0.611 0.597 20 | 20 0.785 70.075 3.036 0.823 0.750 21 | 21 0.807 16.886 1.676 0.940 0.707 22 | 22 0.192 26.324 7.906 0.148 0.271 23 | 23 0.501 95.868 12.573 0.448 0.568 24 | 25 0.577 43.816 3.722 0.473 0.739 25 | 26 0.637 19.146 2.833 0.516 0.834 26 | 28 0.784 24.482 2.453 0.782 0.787 27 | 29 0.713 42.197 3.706 0.804 0.641 28 | 30 0.595 18.899 4.883 0.927 0.438 29 | 31 0.572 21.459 3.310 0.825 0.438 30 | 32 0.570 69.302 7.727 0.569 0.572 31 | 33 0.664 43.370 3.353 0.913 0.522 32 | 34 0.726 33.706 2.257 0.735 0.718 33 | 35 0.807 16.549 2.577 0.956 0.698 34 | 36 0.833 54.818 2.208 0.804 0.865 35 | 37 0.000 54.713 40.668 0.000 0.000 36 | 39 0.612 15.636 1.764 0.623 0.601 37 | 40 0.382 44.311 8.292 0.985 0.237 38 | 41 0.145 50.769 11.584 0.956 0.078 39 | 42 0.460 79.687 13.048 0.540 0.400 40 | 43 0.710 16.234 3.407 0.934 0.573 41 | 44 0.000 inf inf 0.000 0.000 42 | 45 0.327 65.696 9.678 0.327 0.328 43 | WARNING: Average values only computed on 37 of 38 cases! 44 | DM average 0.604472275106 +/- 0.198883449303 45 | HD average 36.682432916 +/- 21.494814922 46 | ASSD average 5.91418383668 +/- 6.62089619693 47 | Prec. average 0.745171723029 +/- 0.238664299874 48 | Rec. average 0.557729375289 +/- 0.212611149046 49 | INFO: Evaluating in sequence space.. 50 | Metrics: 51 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 52 | 03 0.622 35.369 6.969 0.973 0.457 53 | 04 0.763 61.188 3.838 0.731 0.797 54 | 05 0.382 33.941 10.621 0.998 0.236 55 | 06 0.814 19.900 2.872 0.914 0.733 56 | 07 0.878 11.225 1.954 0.908 0.850 57 | 08 0.716 25.981 5.210 0.978 0.565 58 | 09 0.592 73.973 7.164 0.526 0.675 59 | 10 0.506 30.150 7.229 0.983 0.340 60 | 11 0.554 29.698 4.405 0.961 0.389 61 | 12 0.832 22.045 2.540 0.967 0.730 62 | 13 0.811 23.622 2.968 0.846 0.779 63 | 15 0.801 15.297 2.185 0.816 0.787 64 | 17 0.780 16.155 3.292 0.717 0.855 65 | 18 0.791 15.588 2.242 0.942 0.681 66 | 19 0.634 18.493 3.492 0.629 0.639 67 | 20 0.878 67.683 3.116 0.908 0.851 68 | 21 0.821 16.155 2.288 0.932 0.733 69 | 22 0.276 23.043 7.175 0.212 0.396 70 | 23 0.489 98.362 14.512 0.428 0.570 71 | 25 0.603 45.200 4.147 0.487 0.792 72 | 26 0.674 18.493 3.391 0.537 0.905 73 | 28 0.832 27.659 2.628 0.822 0.842 74 | 29 0.751 42.532 3.857 0.847 0.675 75 | 30 0.628 19.209 5.137 0.965 0.466 76 | 31 0.609 20.125 3.457 0.853 0.473 77 | 32 0.608 66.880 8.212 0.587 0.630 78 | 33 0.679 44.598 4.178 0.913 0.540 79 | 34 0.811 32.863 2.210 0.803 0.820 80 | 35 0.825 15.588 2.625 0.957 0.726 81 | 36 0.844 52.735 3.082 0.802 0.891 82 | 37 0.000 54.166 40.665 0.000 0.000 83 | 39 0.697 12.728 2.067 0.700 0.694 84 | 40 0.386 45.200 8.213 0.970 0.241 85 | 41 0.153 52.048 12.124 0.956 0.083 86 | 42 0.470 82.541 14.833 0.533 0.420 87 | 43 0.734 17.748 3.718 0.953 0.596 88 | 44 0.000 inf inf 0.000 0.000 89 | 45 0.416 62.498 8.325 0.400 0.433 90 | WARNING: Average values only computed on 37 of 38 cases! 91 | DM average 0.639412835501 +/- 0.204339206399 92 | HD average 36.5049517465 +/- 21.8430361378 93 | ASSD average 6.13351671366 +/- 6.66164025046 94 | Prec. average 0.769093840357 +/- 0.23649270707 95 | Rec. average 0.602409592261 +/- 0.225224751767 96 | -------------------------------------------------------------------------------- /logs/exp01.b.thr500.log: -------------------------------------------------------------------------------- 1 | INFO: Reverting segmentations.... 2 | INFO: Evaluating in original space... 3 | Metrics: 4 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 5 | 03 0.612 33.110 6.774 0.977 0.445 6 | 04 0.706 62.907 3.831 0.696 0.717 7 | 05 0.370 32.120 10.904 1.000 0.227 8 | 06 0.785 19.473 2.514 0.894 0.700 9 | 07 0.868 12.537 1.503 0.924 0.819 10 | 08 0.688 26.906 6.040 0.945 0.541 11 | 09 0.569 71.792 6.021 0.529 0.615 12 | 10 0.480 27.873 7.593 0.945 0.322 13 | 11 0.519 31.149 4.360 0.914 0.362 14 | 12 0.778 20.864 2.869 0.912 0.678 15 | 13 0.777 23.620 3.010 0.837 0.725 16 | 15 0.688 19.963 2.740 0.717 0.661 17 | 17 0.774 15.496 2.804 0.722 0.834 18 | 18 0.745 16.524 2.114 0.921 0.626 19 | 19 0.604 18.972 3.089 0.611 0.597 20 | 20 0.785 70.075 3.036 0.823 0.750 21 | 21 0.807 16.886 1.676 0.940 0.707 22 | 22 0.192 26.324 7.906 0.148 0.271 23 | 23 0.503 95.868 12.358 0.450 0.568 24 | 25 0.582 27.225 3.146 0.480 0.739 25 | 26 0.637 19.146 2.833 0.516 0.834 26 | 28 0.784 24.482 2.453 0.782 0.787 27 | 29 0.713 42.197 3.706 0.804 0.641 28 | 30 0.595 18.899 4.883 0.927 0.438 29 | 31 0.572 21.459 3.310 0.825 0.438 30 | 32 0.570 69.302 7.727 0.569 0.572 31 | 33 0.666 38.538 3.106 0.920 0.522 32 | 34 0.730 11.627 1.968 0.742 0.718 33 | 35 0.807 16.549 2.577 0.956 0.698 34 | 36 0.833 54.818 2.208 0.804 0.865 35 | 37 0.000 56.063 45.213 0.000 0.000 36 | 39 0.616 15.636 1.771 0.641 0.593 37 | 40 0.382 44.311 8.292 0.985 0.237 38 | 41 0.145 50.769 11.584 0.956 0.078 39 | 42 0.460 77.700 12.949 0.542 0.400 40 | 43 0.710 16.234 3.407 0.934 0.573 41 | 44 0.000 inf inf 0.000 0.000 42 | 45 0.329 32.797 9.251 0.330 0.328 43 | WARNING: Average values only computed on 37 of 38 cases! 44 | DM average 0.604965515652 +/- 0.198850735751 45 | HD average 34.600299052 +/- 21.1861921588 46 | ASSD average 5.98717565547 +/- 7.27350326468 47 | Prec. average 0.746436964067 +/- 0.238070343915 48 | Rec. average 0.557493392003 +/- 0.212567345584 49 | INFO: Evaluating in sequence space.. 50 | Metrics: 51 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 52 | 03 0.622 35.369 6.969 0.973 0.457 53 | 04 0.763 61.188 3.838 0.731 0.797 54 | 05 0.382 33.941 10.621 0.998 0.236 55 | 06 0.814 19.900 2.872 0.914 0.733 56 | 07 0.878 11.225 1.954 0.908 0.850 57 | 08 0.716 25.981 5.210 0.978 0.565 58 | 09 0.592 73.973 7.164 0.526 0.675 59 | 10 0.506 30.150 7.229 0.983 0.340 60 | 11 0.554 29.698 4.405 0.961 0.389 61 | 12 0.832 22.045 2.540 0.967 0.730 62 | 13 0.811 23.622 2.968 0.846 0.779 63 | 15 0.801 15.297 2.185 0.816 0.787 64 | 17 0.780 16.155 3.292 0.717 0.855 65 | 18 0.791 15.588 2.242 0.942 0.681 66 | 19 0.634 18.493 3.492 0.629 0.639 67 | 20 0.878 67.683 3.116 0.908 0.851 68 | 21 0.821 16.155 2.288 0.932 0.733 69 | 22 0.276 23.043 7.175 0.212 0.396 70 | 23 0.491 98.362 14.225 0.431 0.570 71 | 25 0.608 23.431 3.636 0.493 0.792 72 | 26 0.674 18.493 3.391 0.537 0.905 73 | 28 0.832 27.659 2.628 0.822 0.842 74 | 29 0.751 42.532 3.857 0.847 0.675 75 | 30 0.628 19.209 5.137 0.965 0.466 76 | 31 0.609 20.125 3.457 0.853 0.473 77 | 32 0.608 66.880 8.212 0.587 0.630 78 | 33 0.681 40.025 3.785 0.922 0.540 79 | 34 0.818 11.225 1.780 0.816 0.820 80 | 35 0.825 15.588 2.625 0.957 0.726 81 | 36 0.844 52.735 3.082 0.802 0.891 82 | 37 0.000 55.399 45.664 0.000 0.000 83 | 39 0.710 12.728 1.954 0.730 0.691 84 | 40 0.386 45.200 8.213 0.970 0.241 85 | 41 0.153 52.048 12.124 0.956 0.083 86 | 42 0.473 78.975 14.152 0.541 0.420 87 | 43 0.734 17.748 3.718 0.953 0.596 88 | 44 0.000 inf inf 0.000 0.000 89 | 45 0.418 30.150 7.802 0.405 0.433 90 | WARNING: Average values only computed on 37 of 38 cases! 91 | DM average 0.640332742385 +/- 0.204396510784 92 | HD average 34.2708206459 +/- 21.5800843706 93 | ASSD average 6.18924271022 +/- 7.35658109836 94 | Prec. average 0.771076910845 +/- 0.23577757509 95 | Rec. average 0.602328430018 +/- 0.225192380659 96 | -------------------------------------------------------------------------------- /logs/exp01.b.thr750.log: -------------------------------------------------------------------------------- 1 | INFO: Reverting segmentations.... 2 | INFO: Evaluating in original space... 3 | Metrics: 4 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 5 | 03 0.612 33.110 6.774 0.977 0.445 6 | 04 0.706 62.907 3.831 0.696 0.717 7 | 05 0.370 32.120 10.904 1.000 0.227 8 | 06 0.785 19.473 2.514 0.894 0.700 9 | 07 0.868 12.537 1.503 0.924 0.819 10 | 08 0.688 26.906 6.040 0.945 0.541 11 | 09 0.569 71.792 6.021 0.529 0.615 12 | 10 0.480 27.873 7.593 0.945 0.322 13 | 11 0.505 41.759 5.610 0.911 0.350 14 | 12 0.778 20.864 2.869 0.912 0.678 15 | 13 0.777 23.620 3.010 0.837 0.725 16 | 15 0.688 19.963 2.740 0.717 0.661 17 | 17 0.774 15.496 2.804 0.722 0.834 18 | 18 0.745 16.524 2.114 0.921 0.626 19 | 19 0.604 18.972 3.089 0.611 0.597 20 | 20 0.785 70.075 3.036 0.823 0.750 21 | 21 0.807 16.886 1.676 0.940 0.707 22 | 22 0.192 26.324 7.906 0.148 0.271 23 | 23 0.503 95.868 12.358 0.450 0.568 24 | 25 0.582 27.225 3.146 0.480 0.739 25 | 26 0.637 19.146 2.833 0.516 0.834 26 | 28 0.784 24.482 2.453 0.782 0.787 27 | 29 0.713 42.197 3.706 0.804 0.641 28 | 30 0.595 18.899 4.883 0.927 0.438 29 | 31 0.572 21.459 3.310 0.825 0.438 30 | 32 0.570 69.302 7.727 0.569 0.572 31 | 33 0.670 21.356 2.639 0.936 0.522 32 | 34 0.730 11.627 1.968 0.742 0.718 33 | 35 0.807 16.549 2.577 0.956 0.698 34 | 36 0.836 28.027 1.752 0.809 0.865 35 | 37 0.000 56.063 45.213 0.000 0.000 36 | 39 0.616 15.636 1.771 0.641 0.593 37 | 40 0.382 44.311 8.292 0.985 0.237 38 | 41 0.145 50.769 11.584 0.956 0.078 39 | 42 0.460 77.700 12.949 0.542 0.400 40 | 43 0.710 16.234 3.407 0.934 0.573 41 | 44 0.000 inf inf 0.000 0.000 42 | 45 0.329 32.797 9.251 0.330 0.328 43 | WARNING: Average values only computed on 37 of 38 cases! 44 | DM average 0.604796246415 +/- 0.199139222827 45 | HD average 33.698604668 +/- 21.0605559407 46 | ASSD average 5.99603006615 +/- 7.28102296857 47 | Prec. average 0.746939170835 +/- 0.238386077524 48 | Rec. average 0.557159681452 +/- 0.212883344243 49 | INFO: Evaluating in sequence space.. 50 | Metrics: 51 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 52 | 03 0.622 35.369 6.969 0.973 0.457 53 | 04 0.763 61.188 3.838 0.731 0.797 54 | 05 0.382 33.941 10.621 0.998 0.236 55 | 06 0.814 19.900 2.872 0.914 0.733 56 | 07 0.878 11.225 1.954 0.908 0.850 57 | 08 0.716 25.981 5.210 0.978 0.565 58 | 09 0.592 73.973 7.164 0.526 0.675 59 | 10 0.506 30.150 7.229 0.983 0.340 60 | 11 0.538 43.784 6.218 0.959 0.374 61 | 12 0.832 22.045 2.540 0.967 0.730 62 | 13 0.811 23.622 2.968 0.846 0.779 63 | 15 0.801 15.297 2.185 0.816 0.787 64 | 17 0.780 16.155 3.292 0.717 0.855 65 | 18 0.791 15.588 2.242 0.942 0.681 66 | 19 0.634 18.493 3.492 0.629 0.639 67 | 20 0.878 67.683 3.116 0.908 0.851 68 | 21 0.821 16.155 2.288 0.932 0.733 69 | 22 0.276 23.043 7.175 0.212 0.396 70 | 23 0.491 98.362 14.225 0.431 0.570 71 | 25 0.608 23.431 3.636 0.493 0.792 72 | 26 0.674 18.493 3.391 0.537 0.905 73 | 28 0.832 27.659 2.628 0.822 0.842 74 | 29 0.751 42.532 3.857 0.847 0.675 75 | 30 0.628 19.209 5.137 0.965 0.466 76 | 31 0.609 20.125 3.457 0.853 0.473 77 | 32 0.608 66.880 8.212 0.587 0.630 78 | 33 0.685 17.748 3.304 0.935 0.540 79 | 34 0.818 11.225 1.780 0.816 0.820 80 | 35 0.825 15.588 2.625 0.957 0.726 81 | 36 0.848 27.659 2.452 0.809 0.891 82 | 37 0.000 55.399 45.664 0.000 0.000 83 | 39 0.710 12.728 1.954 0.730 0.691 84 | 40 0.386 45.200 8.213 0.970 0.241 85 | 41 0.153 52.048 12.124 0.956 0.083 86 | 42 0.473 78.975 14.152 0.541 0.420 87 | 43 0.734 17.748 3.718 0.953 0.596 88 | 44 0.000 inf inf 0.000 0.000 89 | 45 0.418 30.150 7.802 0.405 0.433 90 | WARNING: Average values only computed on 37 of 38 cases! 91 | DM average 0.640128160788 +/- 0.204714043851 92 | HD average 33.3716792076 +/- 21.5690268384 93 | ASSD average 6.20821983751 +/- 7.36330116286 94 | Prec. average 0.771599112375 +/- 0.236019643943 95 | Rec. average 0.601933498874 +/- 0.225578959238 96 | -------------------------------------------------------------------------------- /documentation/niftimetadata: -------------------------------------------------------------------------------- 1 | 2 | NifTi Orientation and Location 3 | ############################## 4 | 5 | The NifTi standard describes three ways to define an images orientation and location, which can be found under 6 | http://nifti.nimh.nih.gov/nifti-1/documentation/nifti1fields/nifti1fields_pages/qsform.html 7 | 8 | Most importantly are the values in "qform_code" and "sform_code", who determine which of the three approaches are available in the header of the current image and which one to pick. Generally theres is: 9 | - METHOD 1 (the "old" way, used only when qform_code = 0): 10 | - METHOD 2 (used when qform_code > 0, which should be the "normal" case): 11 | - METHOD 3 (used when sform_code > 0): 12 | It is sadly not defined what to do if "qform_code" > 0 and "sform_code" > 0 at the same time. The standard leaves it to the application to make its pick, which leads to inconsisten behaviour. 13 | 14 | Intended usage 15 | ############## 16 | Mainly described under 17 | http://nifti.nimh.nih.gov/nifti-1/documentation/nifti1fields/nifti1fields_pages/qsform.html 18 | 19 | The "qform" is intended for the real-world- / scanner-coordinate system, while the "sform" is intended for mapping to a custom space, such as the MNI template used in neuroscience. The value of their respective codes can give a hint on which space they transform to, but one can not rely on this: 20 | 0 - unknown 21 | 1 - scanner/real-world 22 | 2 - aligned 23 | 3 - talairach 24 | 4 - mni 25 | Other positive values are also possible, but then with custom meaning attached and not portable. Negative values should never be used, although they can theoretically be set (field type is short, not ushort). Using them would elad to highly incosistent behaviour in the way program handle the images (as some check for "xform_code" > 0, while others use "xform_code" == 0). 26 | 27 | Handling of the orientation information by different programs 28 | ############################################################# 29 | nibabel: 30 | - nibabel checks the qform_ as well as the sform_code and returns under header.get_affine() the most apropriate pick 31 | - nibabel preferes sform over qform, i.e. if both are present, the sform transformation is used 32 | - upon updating the pixel spacing (called zooms) or the offset (origin), the qform is updated correctly but not the sform, although both should be updated for consistency 33 | 34 | MedPy: 35 | - since based on nibabel, shares its behaviour 36 | - the get_pixel_spacing() as well as the get_origin() methods return the qform definitions, not the sform ones, independently on what nibabel consideres the best affine 37 | 38 | cmtk: 39 | - cmtk checks the qform_ as well as the sform_code and consideres the most apropriate pick 40 | - cmtk preferes qform over sform, i.e. if both are present, the qform transformation is used 41 | - upon saving a volume as a NifTi image, cmtk sets the qform to a diagonal matrix with a qform_code of 0 and places the volumes transform into the sform with a sform_code of 1 42 | 43 | elastix/ITK: 44 | - loading behaviour is unknown, but seems to favour qform 45 | - when reslicing the image, both qform and sform are updated 46 | - sometimes seems to set the qform_code to 2, which is somewhat consistent with the standard, as 2 - aligned 47 | 48 | SPM: 49 | - preferes sform over qform, yes, it even seems that it does not check the qform_ and sform_code, but always picks the qform transformation 50 | - when aligning to the std space, SPM saves the images with correct new sform and qform, as it seems, and sets both codes to a the value 2 (why? since ppoints to real-world) 51 | 52 | Agreed on behaviour 53 | ################### 54 | In the pipeline, I enforce setting qform_code as well as sform_code to "1" resp. "2" and keep the sform as well as the qform aligned. 55 | 56 | 57 | -------------------------------------------------------------------------------- /scripts/extract_features_stdspace.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | """ 4 | Extract selected features from an image and save them under a fixed file name structure. 5 | As first argument, supply the source folder with the image channels, as second the mask image and as third the target folder. 6 | Note: Does not overwrite existing feature files. 7 | """ 8 | 9 | import os 10 | import sys 11 | import numpy 12 | import itertools 13 | 14 | from medpy.io import load, header 15 | from medpy.features.intensity import intensities, centerdistance, centerdistance_xdminus1, local_mean_gauss, local_histogram, hemispheric_difference, median, guassian_gradient_magnitude 16 | from medpy.features.intensity import indices as indices_feature 17 | 18 | trg_dtype = numpy.float32 19 | features_to_extract = [ 20 | ('flair_tra', intensities, [], False), 21 | ('flair_tra', local_mean_gauss, [3], True), 22 | ('flair_tra', local_mean_gauss, [5], True), 23 | ('flair_tra', local_mean_gauss, [7], True), 24 | #('flair_tra', guassian_gradient_magnitude, [5], True), 25 | #('flair_tra', median, [7], True), 26 | ('flair_tra', local_histogram, [11, 'image', (0, 100), 5, None, None, 'ignore', 0], False), #11 bins, 5*2=10mm region 27 | ('flair_tra', local_histogram, [11, 'image', (0, 100), 10, None, None, 'ignore', 0], False), #11 bins, 10*2=20mm region 28 | ('flair_tra', local_histogram, [11, 'image', (0, 100), 15, None, None, 'ignore', 0], False), #11 bins, 15*2=30mm region 29 | ('flair_tra', centerdistance_xdminus1, [0], True), 30 | ('flair_tra', centerdistance_xdminus1, [1], True), 31 | ('flair_tra', centerdistance_xdminus1, [2], True), 32 | ('flair_tra', hemispheric_difference, [6, 9, 0], True), 33 | ('flair_tra', hemispheric_difference, [6, 15, 0], True), 34 | ('flair_tra', hemispheric_difference, [9, 15, 0], True), 35 | ('flair_tra', hemispheric_difference, [6, 12, 0], True), 36 | ('flair_tra', hemispheric_difference, [9, 12, 0], True), 37 | ('flair_tra', hemispheric_difference, [12, 15, 0], True), 38 | ('flair_tra', hemispheric_difference, [3, 15, 0], True), 39 | ('flair_tra', hemispheric_difference, [3, 12, 0], True), 40 | ('flair_tra', hemispheric_difference, [6, 6, 0], True), 41 | ('flair_tra', hemispheric_difference, [9, 9, 0], True), 42 | ('flair_tra', hemispheric_difference, [3, 9, 0], True), 43 | ('flair_tra', hemispheric_difference, [3, 6, 0], True), 44 | ('flair_tra', hemispheric_difference, [12, 12, 0], True), 45 | ('flair_tra', hemispheric_difference, [15, 15, 0], True) 46 | ] 47 | 48 | def main(): 49 | # loading the image mask 50 | m = load(sys.argv[2])[0].astype(numpy.bool) 51 | 52 | # extracting the required features and saving them 53 | for sequence, function_call, function_arguments, voxelspacing in features_to_extract: 54 | if not isfv(sys.argv[3], sequence, function_call, function_arguments): 55 | #print sequence, function_call.__name__, function_arguments 56 | i, h = load('{}/{}.nii.gz'.format(sys.argv[1], sequence)) 57 | call_arguments = list(function_arguments) 58 | if voxelspacing: call_arguments.append(header.get_pixel_spacing(h)) 59 | call_arguments.append(m) 60 | fv = function_call(i, *call_arguments) 61 | savefv(fv, sys.argv[3], sequence, function_call, function_arguments) 62 | 63 | def savefv(fv, trgdir, seq, fcall, fargs): 64 | """Saves the supplied feature vector under a fixed naming rule.""" 65 | name = 'feature.{}.{}.{}'.format(seq, fcall.func_name, '_'.join(['arg{}'.format(i) for i in fargs])) 66 | with open('{}/{}.npy'.format(trgdir, name), 'wb') as f: 67 | numpy.save(f, fv.astype(trg_dtype)) 68 | 69 | def isfv(trgdir, seq, fcall, fargs): 70 | name = 'feature.{}.{}.{}'.format(seq, fcall.func_name, '_'.join(['arg{}'.format(i) for i in fargs])) 71 | return os.path.exists('{}/{}.npy'.format(trgdir, name)) 72 | 73 | if __name__ == "__main__": 74 | main() 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /scripts/evaluate_segmentations.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | """ 4 | Evaluate the segmentation created. 5 | arg1: the segmentation result for each case, with a {} in place of the case number 6 | arg2: the ground truth segmentation, with a {} in place of the case number 7 | arg3: the cases mask file, with a {} in place of the case number 8 | arg4+: the cases to evaluate 9 | """ 10 | 11 | import sys 12 | import math 13 | import time 14 | from multiprocessing.pool import Pool 15 | 16 | import numpy 17 | 18 | from medpy.io import load, header 19 | from medpy.metric import dc, hd, assd, precision, recall 20 | 21 | # constants 22 | n_jobs = 6 23 | silent = True 24 | 25 | def main(): 26 | 27 | # catch parameters 28 | segmentation_base_string = sys.argv[1] 29 | ground_truth_base_string = sys.argv[2] 30 | mask_file_base_string = sys.argv[3] 31 | cases = sys.argv[4:] 32 | 33 | # evaluate each case and collect the scores 34 | hds = [] 35 | assds = [] 36 | precisions = [] 37 | recalls = [] 38 | dcs = [] 39 | 40 | # load images and apply mask to segmentation and ground truth (to remove ground truth fg outside of brain mask) 41 | splush = [load(segmentation_base_string.format(case)) for case in cases] 42 | tplush = [load(ground_truth_base_string.format(case)) for case in cases] 43 | masks = [load(mask_file_base_string.format(case))[0].astype(numpy.bool) for case in cases] 44 | 45 | s = [s.astype(numpy.bool) & m for (s, _), m in zip(splush, masks)] 46 | t = [t.astype(numpy.bool) & m for (t, _), m in zip(tplush, masks)] 47 | hs = [h for _, h in splush] 48 | ht = [h for _, h in tplush] 49 | 50 | # compute and append metrics (Pool-processing) 51 | pool = Pool(n_jobs) 52 | dcs = pool.map(wdc, zip(t, s)) 53 | precisions = pool.map(wprecision, zip(s, t)) 54 | recalls = pool.map(wrecall, zip(s, t)) 55 | hds = pool.map(whd, zip(t, s, [header.get_pixel_spacing(h) for h in ht])) 56 | assds = pool.map(wassd, zip(t, s, [header.get_pixel_spacing(h) for h in ht])) 57 | 58 | # print case-wise results 59 | print 'Metrics:' 60 | print 'Case\tDC[0,1]\tHD(mm)\tP2C(mm)\tprec.\trecall' 61 | for case, _dc, _hd, _assd, _pr, _rc in zip(cases, dcs, hds, assds, precisions, recalls): 62 | print '{}\t{:>3,.3f}\t{:>4,.3f}\t{:>4,.3f}\t{:>3,.3f}\t{:>3,.3f}'.format(case, _dc, _hd, _assd, _pr, _rc) 63 | 64 | # check for nan/inf values of failed cases and signal warning 65 | mask = numpy.isfinite(hds) 66 | if not numpy.all(mask): 67 | print 'WARNING: Average values only computed on {} of {} cases!'.format(numpy.count_nonzero(mask), mask.size) 68 | 69 | print 'DM average\t{} +/- {} (Median: {})'.format(numpy.asarray(dcs)[mask].mean(), numpy.asarray(dcs)[mask].std(), numpy.median(numpy.asarray(dcs)[mask])) 70 | print 'HD average\t{} +/- {} (Median: {})'.format(numpy.asarray(hds)[mask].mean(), numpy.asarray(hds)[mask].std(), numpy.median(numpy.asarray(hds)[mask])) 71 | print 'ASSD average\t{} +/- {} (Median: {})'.format(numpy.asarray(assds)[mask].mean(), numpy.asarray(assds)[mask].std(), numpy.median(numpy.asarray(assds)[mask])) 72 | print 'Prec. average\t{} +/- {} (Median: {})'.format(numpy.asarray(precisions)[mask].mean(), numpy.asarray(precisions)[mask].std(), numpy.median(numpy.asarray(precisions)[mask])) 73 | print 'Rec. average\t{} +/- {} (Median: {})'.format(numpy.asarray(recalls)[mask].mean(), numpy.asarray(recalls)[mask].std(), numpy.median(numpy.asarray(recalls)[mask])) 74 | 75 | def wdc(x): 76 | return dc(*x) 77 | def whd(x): 78 | try: 79 | val = hd(*x) 80 | except RuntimeError: 81 | val = numpy.inf 82 | return val 83 | def wprecision(x): 84 | return precision(*x) 85 | def wrecall(x): 86 | return recall(*x) 87 | def wassd(x): 88 | try: 89 | val = assd(*x) 90 | except RuntimeError: 91 | val = numpy.inf 92 | return val 93 | 94 | if __name__ == "__main__": 95 | main() 96 | -------------------------------------------------------------------------------- /pop_sequencesegmentations.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ##### 4 | # Tranform all segmentation binary images to the base sequence space. 5 | ##### 6 | 7 | ## Changelog 8 | # 2014-03-25 Adapted to work with arbitrary base sequence, treating flair_tra special. 9 | # 2013-11-06 added an additional step, correcting precision errors in the image header 10 | # 2013-11-05 optimized 11 | # 2013-10-21 created 12 | 13 | # include shared information 14 | source $(dirname $0)/include.sh 15 | 16 | # functions 17 | ### 18 | # Binary resampling of a mask 19 | ### 20 | function bresample () 21 | { 22 | srcfile=$1 23 | trgfile=$2 24 | vs=$3 25 | 26 | # warn and skip if source file not present 27 | if [ ! -f "${srcfile}" ]; then 28 | log 3 "Original round truth for case not found under ${srcfile}. Skipping." "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 29 | return 30 | fi 31 | 32 | # process if target file not yet existing 33 | if [ ! -f "${trgfile}" ]; then 34 | log 1 "Resampling to ${trgfile} with ${vs}" "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 35 | runcond "medpy_resample.py ${srcfile} ${trgfile} ${vs} -o1" 36 | fi 37 | } 38 | 39 | # main code 40 | if [ ${basesequence} == "flair_tra" ]; then 41 | log 2 "Adapting all expert segmentation to (possibly resampled) flair_tra space" "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 42 | # check on first flair case, whether a resampling on the flair images has been conducted 43 | ovs=( $(voxelspacing "${originals}/${images[0]}/flair_tra.${imgfiletype}") ) 44 | nvs=( $(voxelspacing "${sequencespace}/${images[0]}/flair_tra.${imgfiletype}") ) 45 | equal=true 46 | for i in "${!ovs[@]}"; do 47 | if [ ! "${ovs[$i]}" == "${nvs[$i]}" ]; then 48 | equal=false 49 | break 50 | fi 51 | done 52 | 53 | # if equal, simply link masks, if not, resample masks 54 | if $equal; then 55 | log 2 "Detected flair_tra sequence to not have been resampled. Performing linking." "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 56 | cwd=$(pwd) 57 | for i in "${images[@]}"; do 58 | lncond "${cwd}/${segmentations}/${i}.${imgfiletype}" "${sequencesegmentations}/${i}.${imgfiletype}" 59 | done 60 | else 61 | log 2 "Detected flair_tra sequence to have been resampled. Performing binary resampling." "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 62 | for i in "${images[@]}"; do 63 | bresample "${segmentations}/${i}.${imgfiletype}" "${sequencesegmentations}/${i}.${imgfiletype}" $(joinarr "," ${nvs[@]}) 64 | done 65 | fi 66 | 67 | else 68 | # transfom using the flair transformation matrix 69 | log 2 "Tranforming all expert segmentation to ${basesequence} space" "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 70 | 71 | tmpdir=`mktemp -d` 72 | for i in "${images[@]}"; do 73 | 74 | # continue if target file already exists 75 | if [ -f "${sequencesegmentations}/${i}.${imgfiletype}" ]; then 76 | continue 77 | fi 78 | 79 | # edit transformation file (strange, array using syntax, since otherwise quotes '' are passed to sed) 80 | command=(sed -e 's/(FinalBSplineInterpolationOrder 3)/(FinalBSplineInterpolationOrder 0)/g' -e 's/(ResultImagePixelType \"float\")/(ResultImagePixelType \"char\")/g' "${sequencespace}/${i}/flair_tra.txt") 81 | #echo "Command: \"${command[*]}\"" 82 | "${command[@]}" > "${tmpdir}/tf.txt" 83 | 84 | # run transformation 85 | runcond "transformix -out ${tmpdir} -tp ${tmpdir}/tf.txt -in ${segmentations}/${i}.${imgfiletype}" /dev/null 86 | 87 | # copy transformed binary segmentation file 88 | runcond "mv ${tmpdir}/result.${imgfiletype} ${sequencesegmentations}/${i}.${imgfiletype}" 89 | 90 | # adapt header, as elastix seems to use another precision, which might lead to error later 91 | runcond "${scripts}/pass_header.py ${sequencesegmentations}/${i}.${imgfiletype} ${sequencespace}/${i}/${basesequence}.${imgfiletype}" 92 | 93 | emptydircond ${tmpdir} 94 | done 95 | rmdircond ${tmpdir} 96 | fi 97 | 98 | log 2 "Done." "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 99 | -------------------------------------------------------------------------------- /experiments/ParallelTreesAndAlternatingNodeMixedForests: -------------------------------------------------------------------------------- 1 | Description 2 | ########### 3 | Experiment conducted with Michael from Heidelberg, where compared parallel forests with normal forests and alternating nodes. 4 | 5 | Overall Conclusion 6 | ################## 7 | Parallel forests are not very promising. Alternating node mixed forests perform significantly better than RDF and en-pa with ETs. 8 | 9 | Configurations 10 | ############## 11 | A) RDF Random Decision Forest, 200 trees 12 | B) ET Extra Tree Forest, 200 trees 13 | C) parallel 100 trees from A) and 100 trees from B) combined for voting 14 | D) alternating Mixed Decision Forest with alternating nodes i.e. 200 trees with nodes alternating between ET and RDF types 15 | 16 | 17 | Exp 01: Evaluation on one case 18 | ############################## 19 | Conclusion: 20 | Parallel configuration does not seem to lead to any gain, but the alternating is more promising. 21 | 22 | ET: 23 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 24 | 03 0.772 33.136 4.429 0.961 0.645 25 | RDF: 26 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 27 | 03 0.768 33.136 4.504 0.963 0.639 28 | ET+RDF combined in parallel: 29 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 30 | 03 0.771 33.136 4.456 0.963 0.644 31 | ET+RDF alternating nodes: 32 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 33 | 03 0.784 31.464 4.194 0.955 0.665 34 | 35 | 36 | 37 | EXP 02: Evaluating on a couple of cases 38 | ####################################### 39 | Conclusion: 40 | Alternating nodes are significantly (students t-test) better than RDF configuration, but they only perform en-pa with the ET configuration (no significant difference). 41 | Later experiments showed this observation to be true over all images. 42 | 43 | ET+RDF alternating nodes: 44 | Metrics: 45 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 46 | 03 0.784 31.464 4.194 0.955 0.665 47 | 05 0.628 24.187 6.961 0.997 0.458 48 | 07 0.887 13.748 1.736 0.945 0.835 49 | 09 0.683 10.392 2.160 0.801 0.595 50 | 10 0.577 26.325 6.227 0.975 0.409 51 | 11 0.545 28.460 4.479 0.909 0.389 52 | 12 0.799 24.556 3.103 0.954 0.687 53 | 13 0.848 22.450 2.525 0.873 0.825 54 | 15 0.810 11.225 2.230 0.744 0.890 55 | DM average 0.729022712393 +/- 0.116863474967 (Median: 0.783839457771) 56 | HD average 21.4230486134 +/- 7.28374821834 (Median: 24.1867732449) 57 | ASSD average 3.73497668983 +/- 1.76344566554 (Median: 3.10330283165) 58 | Prec. average 0.906054418591 +/- 0.0801092619555 (Median: 0.945259593679) 59 | Rec. average 0.639303346209 +/- 0.179001319346 (Median: 0.664563380282) 60 | 61 | RDF: 62 | Metrics: 63 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 64 | 03 0.768 33.136 4.504 0.963 0.639 65 | 05 0.581 24.187 7.813 0.996 0.411 66 | 07 0.870 15.297 1.979 0.960 0.795 67 | 09 0.600 11.225 2.592 0.813 0.476 68 | 10 0.503 27.000 7.228 0.976 0.339 69 | 11 0.539 29.698 4.659 0.889 0.386 70 | 12 0.718 25.807 4.164 0.976 0.568 71 | 13 0.844 23.431 2.580 0.876 0.815 72 | 15 0.814 11.225 2.176 0.758 0.880 73 | DM average 0.693227016817 +/- 0.131685609312 (Median: 0.718453865337) 74 | HD average 22.3340076441 +/- 7.4961391766 (Median: 24.1867732449) 75 | ASSD average 4.18821780954 +/- 2.02112629691 (Median: 4.16448404939) 76 | Prec. average 0.912045380975 +/- 0.0785194965171 (Median: 0.960248945995) 77 | Rec. average 0.589819571264 +/- 0.191159489112 (Median: 0.568356677846) 78 | 79 | ET: 80 | Metrics: 81 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 82 | 03 0.765 31.464 4.545 0.958 0.636 83 | 05 0.600 23.622 7.485 0.996 0.429 84 | 07 0.884 12.369 1.797 0.943 0.832 85 | 09 0.683 10.817 2.225 0.795 0.598 86 | 10 0.535 29.547 6.783 0.976 0.369 87 | 11 0.602 29.547 4.106 0.936 0.443 88 | 12 0.769 24.920 3.492 0.967 0.638 89 | 13 0.853 22.650 2.471 0.872 0.835 90 | 15 0.818 11.225 2.116 0.757 0.891 91 | DM average 0.7232222222 92 | HD average 21.7956666667 93 | ASSD average 3.8911111111 94 | Prec. average 0.9111111111 95 | Rec. average 0.6301111111 96 | 97 | -------------------------------------------------------------------------------- /logs/exp00.a.log: -------------------------------------------------------------------------------- 1 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 2 | 03 0.612 33.110 6.774 0.977 0.445 3 | 04 0.713 16.472 2.558 0.709 0.717 4 | 05 0.370 32.120 10.904 1.000 0.227 5 | 06 0.785 19.473 2.514 0.894 0.700 6 | 07 0.868 12.537 1.503 0.924 0.819 7 | 08 0.688 26.906 6.040 0.945 0.541 8 | 09 0.632 11.557 1.671 0.651 0.615 9 | 10 0.480 27.873 7.593 0.945 0.322 10 | 11 0.505 41.759 5.610 0.911 0.350 11 | 12 0.778 20.864 2.869 0.912 0.678 12 | 13 0.777 23.620 3.010 0.837 0.725 13 | 15 0.688 19.963 2.740 0.717 0.661 14 | 17 0.774 15.496 2.804 0.722 0.834 15 | 18 0.745 16.524 2.114 0.921 0.626 16 | 19 0.604 18.972 3.089 0.611 0.597 17 | 20 0.793 8.582 1.327 0.842 0.750 18 | 21 0.807 16.886 1.676 0.940 0.707 19 | 22 0.192 26.324 7.906 0.148 0.271 20 | 23 0.488 95.868 13.875 0.442 0.544 21 | 25 0.582 27.225 3.146 0.480 0.739 22 | 26 0.637 19.146 2.833 0.516 0.834 23 | 28 0.784 24.482 2.453 0.782 0.787 24 | 29 0.713 42.197 3.706 0.804 0.641 25 | 30 0.595 18.899 4.883 0.927 0.438 26 | 31 0.572 21.459 3.310 0.825 0.438 27 | 32 0.570 69.302 7.727 0.569 0.572 28 | 33 0.670 21.356 2.639 0.936 0.522 29 | 34 0.730 11.627 1.968 0.742 0.718 30 | 35 0.807 16.549 2.577 0.956 0.698 31 | 36 0.841 16.566 1.330 0.818 0.865 32 | 37 0.000 62.795 40.789 0.000 0.000 33 | 39 0.616 15.636 1.771 0.641 0.593 34 | 40 0.382 44.311 8.292 0.985 0.237 35 | 41 0.145 50.769 11.584 0.956 0.078 36 | 42 0.466 64.157 11.959 0.558 0.400 37 | 43 0.710 16.234 3.407 0.934 0.573 38 | 44 0.000 inf inf 0.000 0.000 39 | 45 0.329 32.797 9.251 0.330 0.328 40 | WARNING: Average values only computed on 37 of 38 cases! 41 | DM average 0.60682874643 +/- 0.19966218161 (Median: 0.637239852553) 42 | HD average 28.65986912 +/- 18.6443144956 (Median: 21.3556169087) 43 | ASSD average 5.68114470627 +/- 6.74206545011 (Median: 3.08853941435) 44 | Prec. average 0.751591090856 +/- 0.236250074025 (Median: 0.825) 45 | Rec. average 0.556500224137 +/- 0.212885359696 (Median: 0.597414880202) 46 | INFO: Evaluating in sequence space.. 47 | Metrics: 48 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 49 | 03 0.622 35.369 6.969 0.973 0.457 50 | 04 0.771 15.000 2.548 0.747 0.797 51 | 05 0.382 33.941 10.621 0.998 0.236 52 | 06 0.814 19.900 2.872 0.914 0.733 53 | 07 0.878 11.225 1.954 0.908 0.850 54 | 08 0.716 25.981 5.210 0.978 0.565 55 | 09 0.673 12.369 2.289 0.671 0.675 56 | 10 0.506 30.150 7.229 0.983 0.340 57 | 11 0.538 43.784 6.218 0.959 0.374 58 | 12 0.832 22.045 2.540 0.967 0.730 59 | 13 0.811 23.622 2.968 0.846 0.779 60 | 15 0.801 15.297 2.185 0.816 0.787 61 | 17 0.780 16.155 3.292 0.717 0.855 62 | 18 0.791 15.588 2.242 0.942 0.681 63 | 19 0.634 18.493 3.492 0.629 0.639 64 | 20 0.890 8.485 1.250 0.933 0.851 65 | 21 0.821 16.155 2.288 0.932 0.733 66 | 22 0.276 23.043 7.175 0.212 0.396 67 | 23 0.469 98.362 15.787 0.418 0.535 68 | 25 0.608 23.431 3.636 0.493 0.792 69 | 26 0.674 18.493 3.391 0.537 0.905 70 | 28 0.832 27.659 2.628 0.822 0.842 71 | 29 0.751 42.532 3.857 0.847 0.675 72 | 30 0.628 19.209 5.137 0.965 0.466 73 | 31 0.609 20.125 3.457 0.853 0.473 74 | 32 0.608 66.880 8.212 0.587 0.630 75 | 33 0.685 17.748 3.304 0.935 0.540 76 | 34 0.818 11.225 1.780 0.816 0.820 77 | 35 0.825 15.588 2.625 0.957 0.726 78 | 36 0.854 15.000 2.066 0.819 0.891 79 | 37 0.000 67.683 41.449 0.000 0.000 80 | 39 0.710 12.728 1.954 0.730 0.691 81 | 40 0.386 45.200 8.213 0.970 0.241 82 | 41 0.153 52.048 12.124 0.956 0.083 83 | 42 0.481 66.476 12.687 0.562 0.420 84 | 43 0.734 17.748 3.718 0.953 0.596 85 | 44 0.000 inf inf 0.000 0.000 86 | 45 0.418 30.150 7.802 0.405 0.433 87 | WARNING: Average values only computed on 37 of 38 cases! 88 | DM average 0.642640369844 +/- 0.205582159904 (Median: 0.684915882521) 89 | HD average 28.510519388 +/- 19.5562670651 (Median: 20.1246117975) 90 | ASSD average 5.86946002322 +/- 6.84513917488 (Median: 3.45744272198) 91 | Prec. average 0.777078322985 +/- 0.233523350995 (Median: 0.846629986245) 92 | Rec. average 0.600986606035 +/- 0.225786259578 (Median: 0.674890350877) 93 | -------------------------------------------------------------------------------- /experiments/RDF_ET_BehaviourInTheFirstFewLayers: -------------------------------------------------------------------------------- 1 | Description 2 | ########### 3 | Experiments conducted with Michael from Heidelberg to get an idea of the forests behaviour in the first few (and potentially most important) layers of the tree. 4 | 5 | Configurations 6 | ############## 7 | The Forest with different configurations are trained on a few exemplary images using restricted depth. The changes in accuracy as well as the selected features at each level are investigated. 8 | 9 | Overall Conclusion 10 | ################## 11 | Overall: 12 | Already the first splits are quite strong and take care of most of the segmentation. Later splits do largely improve HD and ASSD i.e. outliers are excluded and the segmentation border improved. 13 | Overfitting does not seem to be an issue. 14 | 15 | ET only forest: 16 | Intensity-based features (especially gauss and some histogram bins of flair and DW) dominate in the first layers. 17 | After depth 8-10, a kind of saturation is reached and all features are +/- equally chosen for one layer. 18 | Then the feature intensity, gauss3, gauss5, gauss7 dominate the nodes increasingly till the end of the tree. 19 | 20 | Surprisingly, the accuracy surpasses the RDF already at a depth of 2, which is unexpted considering the random cuts. 21 | Compared to the RDF, the ET does not show any tendency of overfitting for the three cases investigated here. 22 | 23 | 24 | RDF only forest: 25 | Intensity-based features (especially gauss and some histogram bins of flair and DW) dominate in the first layers. 26 | After depth 8-10, a saturation is reached and all features are +/- equally chosen. 27 | 28 | Already at a depth of 4, the segmentation quality is quite high. Training deeper than level 9 improves the results for two of the tree cases and lowers them in one. 29 | Some prunning of the tree might be in order to avoid overfitting, although no strong tendency can be observed. 30 | 31 | 32 | Experiment 33 | ########## 34 | 35 | RDF 36 | ### 37 | max_depth=1 38 | No probability >= 0.5, no segmentation 39 | Probability mask displays slight evidence of lesion, a segmenting cut of >=0.2 might have lead to some results. 40 | 41 | max_depth=2 42 | 03 0.390 43.370 10.639 0.993 0.243 43 | 05 0.262 38.066 14.284 1.000 0.151 44 | 07 0.496 25.807 6.486 0.995 0.331 45 | 46 | max_depth=3 47 | 03 0.583 38.536 7.720 0.974 0.417 48 | 05 0.386 34.073 11.302 1.000 0.239 49 | 07 0.693 20.125 4.205 0.983 0.536 50 | 51 | max_depth=4 52 | 03 0.645 35.623 6.611 0.970 0.483 53 | 05 0.430 32.031 10.436 1.000 0.274 54 | 07 0.771 18.000 3.264 0.978 0.636 55 | 56 | max_depth=9 (observed point of saturation) 57 | 03 0.734 33.136 5.109 0.965 0.592 58 | 05 0.540 27.821 8.492 0.997 0.370 59 | 07 0.852 15.297 2.217 0.970 0.759 60 | 61 | max_depth=None 62 | 03 0.760 31.931 4.374 0.972 0.624 63 | 05 0.568 23.034 8.057 0.999 0.397 64 | 07 0.846 15.664 1.746 0.963 0.755 65 | 66 | 67 | ET 68 | ## 69 | max_depth=1 70 | No probability >= 0.5, no segmentation 71 | Probability mask displays slight evidence of lesion, a segmenting cut of >=0.2 might have lead to some results. 72 | 73 | max_depth=2 74 | 03 0.395 40.137 11.336 0.982 0.247 75 | 05 0.292 36.986 14.000 1.000 0.171 76 | 07 0.660 22.045 4.745 0.978 0.498 77 | real 15m48.569s 78 | user 86m0.959s 79 | 80 | max_depth=3 81 | 03 0.599 37.229 7.525 0.973 0.432 82 | 05 0.400 33.136 11.325 0.999 0.250 83 | 07 0.766 18.974 3.386 0.968 0.633 84 | 85 | max_depth=4 86 | 03 0.652 35.369 6.557 0.963 0.492 87 | 05 0.447 32.450 10.462 0.999 0.288 88 | 07 0.808 17.234 2.852 0.960 0.698 89 | 90 | max_depth=9 (observed point of saturation) 91 | 03 0.739 33.541 5.011 0.965 0.598 92 | 05 0.540 26.495 8.495 0.998 0.370 93 | 07 0.867 14.697 2.044 0.955 0.794 94 | 95 | max_depth=None 96 | 03 0.765 31.464 4.545 0.958 0.636 97 | 05 0.600 23.622 7.485 0.996 0.429 98 | 07 0.884 12.369 1.797 0.943 0.832 99 | 100 | -------------------------------------------------------------------------------- /scripts/ttest.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # Compares to evaluation results for their significants according to the paired t-test. 4 | # Note: The paired t-test calculates the T-test on TWO RELATED samples of scores. This is 5 | # a two-sided test for the null hypothesis that 2 related or repeated samples have 6 | # identical average (expected) values. 7 | # @see: http://en.wikipedia.org/wiki/T-test#Dependent_t-test_for_paired_samples 8 | 9 | # arg1: the first evaluation file 10 | # arg2: the second evaluation file 11 | # arg3: pass anything to print out the case-wise results and differences 12 | 13 | pborder = 0.05 14 | 15 | import sys 16 | import numpy 17 | from scipy.stats import ttest_rel 18 | 19 | def parse_evaluation_file(fn): 20 | parse = False 21 | results = {} 22 | with open(fn, 'r') as f: 23 | for line in f.readlines(): 24 | line = line.strip() 25 | if 'Average' in line or 'average' in line: 26 | parse = False 27 | if parse: 28 | vals = line.split('\t') 29 | results[vals[0]] = map(float, vals[1:]) 30 | if 'Case' == line[:4]: 31 | parse = True 32 | headers = line.split('\t') 33 | if 0 == len(results): 34 | print 'Error: Invalid evaluation file {}.'.format(fn) 35 | sys.exit(-1) 36 | return results, headers 37 | 38 | r1, h1 = parse_evaluation_file(sys.argv[1]) 39 | r2, h2 = parse_evaluation_file(sys.argv[2]) 40 | print_casewise = len(sys.argv) > 3 41 | 42 | if not r1.keys() == r2.keys(): 43 | print 'WARNING: The cases in the two evaluation files differ.' 44 | print 'Symmetric difference is: {}'.format(set.symmetric_difference(set(r1.iterkeys()), set(r2.iterkeys()))) 45 | print 'Continuing, but considering common cases only: {}'.format(set.intersection(set(r1.iterkeys()), set(r2.iterkeys()))) 46 | 47 | for key in set.difference(set(r1.keys()), r2.keys()): 48 | del r1[key] 49 | for key in set.difference(set(r2.keys()), r1.keys()): 50 | del r2[key] 51 | 52 | if not h1 == h2: 53 | print 'ERROR: Incompatible quality metrics.' 54 | print 'Evaluation file {} contains {}.'.format(sys.argv[1], h1) 55 | print 'Evaluation file {} contains {}.'.format(sys.argv[2], h2) 56 | sys.exit(-1) 57 | 58 | 59 | # print case-wise if requested 60 | if print_casewise: 61 | print '\nCase\tRun\t{}'.format('\t'.join(h1[1:])) 62 | for key in sorted(r1): 63 | print '{}\tr1\t{}'.format(key, '\t'.join(map(str, r1[key]))) 64 | print '\tr2\t{}'.format('\t'.join(map(str, r2[key]))) 65 | print '\tdiff\t{}'.format('\t'.join(map(str, numpy.subtract(r1[key], r2[key])))) 66 | print 67 | 68 | 69 | # remove failed cases 70 | failedno = 0 71 | failedkey = [] 72 | for key, scores in list(r1.iteritems()): 73 | if not numpy.all(numpy.isfinite(scores)): 74 | failedno += 1 75 | failedkey.append(key) 76 | del r1[key] 77 | del r2[key] 78 | for key, scores in list(r2.iteritems()): 79 | if not numpy.all(numpy.isfinite(scores)): 80 | failedno += 1 81 | failedkey.append(key) 82 | del r1[key] 83 | del r2[key] 84 | if not 0 == failedno: 85 | print 'WARNING: Statistics only computed for {} of {} cases, as some segmentations failed in at least one of the compared evaluation results!'.format(len(r1), len(r1) + failedno) 86 | 87 | 88 | # print statistics 89 | print 'Statistical significance between results obtained for run r1 ({}) against run r2 ({}) on {} cases:'.format(sys.argv[1], sys.argv[2], len(r1)) 90 | print 'Applied test: Paired t-test for two related samples of scores.' 91 | print 'Metric\tmean-r1\tmean-r2\tdiff\tt-value\tp-value\tsignificant<{}'.format(pborder) 92 | for idx, metric in enumerate(h1[1:]): 93 | r1v = [x[idx] for x in r1.itervalues()] 94 | r2v = [x[idx] for x in r2.itervalues()] 95 | t, p = ttest_rel(r1v, r2v) 96 | print '{}\t{:4.3f}\t{:4.3f}\t{:4.3f}\t{:4.3f}\t{:4.3f}\t{}'.format(metric, numpy.mean(r1v), numpy.mean(r2v), numpy.mean(r1v)-numpy.mean(r2v), float(t), p, pthr]-tpli[m>thr])) / float(len(i[m>thr])) 43 | 44 | # mutual information 45 | mu = mutual_information(i[m>thr], tpli[m>thr]) 46 | 47 | # print 48 | print '{};{};{}'.format(sys.argv[1], ssd, mu) 49 | 50 | def clean(i, cval = 0): 51 | """ 52 | Removes all nan and inf from the image and replace them with a constant value. 53 | """ 54 | i[numpy.isnan(i)] = 0 55 | i[numpy.isinf(i)] = 0 56 | return i 57 | 58 | def gauss(i, h, sigma=6): 59 | """ 60 | Applies a gaussian smoothing to the image with the supplied kernel size in mmm. 61 | """ 62 | sigmas = [sigma * ps for ps in header.get_pixel_spacing(h)] 63 | i = gaussian_filter(i, sigma=sigmas) 64 | return i 65 | 66 | def resample(img, hdr, ps): 67 | """ 68 | Resamples the image i to the provided pixel spacing. 69 | """ 70 | # compute zoom values 71 | zoom_factors = [old / float(new) for new, old in zip(ps, header.get_pixel_spacing(hdr))] 72 | 73 | # zoom image 74 | img = zoom(img, zoom_factors, order=2) # order = bspline order 75 | 76 | # set new voxel spacing 77 | header.set_pixel_spacing(hdr, ps) 78 | 79 | # return image and header 80 | return img, hdr 81 | 82 | 83 | def align(i, h, refi, refh): 84 | """ 85 | Aligns the image i to the reference image refi. 86 | Note that this might include cropping and resampling. 87 | Note that only works for 3D images. 88 | 89 | @param i the input image to align to the reference image 90 | @param h the input image's header (Note: must be of type NifTi) 91 | @param refi the reference image 92 | @param refh the reference image's header 93 | 94 | @return i, h the aligned input image and its modified header 95 | """ 96 | # resample input image if required 97 | if not numpy.all(numpy.asarray(header.get_pixel_spacing(h)) == numpy.asarray(header.get_pixel_spacing(refh))): 98 | i, h = resample(i, h, header.get_pixel_spacing(refh)) 99 | 100 | # shift image to align origins 101 | origin_h = numpy.sign(h.get_qform()[0:3,0:3]).dot(header.get_offset(h)) 102 | origin_refh = numpy.sign(refh.get_qform()[0:3,0:3]).dot(header.get_offset(refh)) 103 | origin_difference_pixel = (origin_h - origin_refh) / numpy.asarray(header.get_pixel_spacing(h)) 104 | # negative values: shift image 1 by this upon inserting (which is the same as cutting the output image) 105 | # positive values: cut image 1 by this at inserting and also cut right side by length of output image plus this value 106 | o = numpy.zeros(refi.shape, refi.dtype) 107 | o_slicer = [] 108 | i_slicer = [] 109 | for j, p in enumerate(origin_difference_pixel): 110 | if p >= 0: 111 | i_slicer.append(slice(0, min(i.shape[j], o.shape[j] - abs(p)))) 112 | o_slicer.append(slice(abs(p), min(i.shape[j] + abs(p), o.shape[j]))) 113 | else: 114 | i_slicer.append(slice(abs(p), min(i.shape[j], o.shape[j] + abs(p)))) 115 | o_slicer.append(slice(0, min(i.shape[j] - abs(p), o.shape[j]))) 116 | 117 | o[o_slicer] = i[i_slicer] 118 | header.set_offset(h, header.get_offset(refh)) 119 | 120 | return o, h 121 | 122 | if __name__ == "__main__": 123 | main() 124 | -------------------------------------------------------------------------------- /logs/eval.all.momentnormalization.log: -------------------------------------------------------------------------------- 1 | INFO: Compute overall evaluation 2 | Metrics: 3 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 4 | 03 0.693 30.150 5.655 0.952 0.545 5 | 04 0.722 81.884 9.996 0.680 0.769 6 | 05 0.409 50.646 11.163 0.959 0.260 7 | 06 0.707 21.213 4.196 0.965 0.558 8 | 07 0.756 12.728 3.357 0.915 0.644 9 | 08 0.543 30.150 7.544 0.973 0.377 10 | 09 0.501 13.748 2.923 0.922 0.344 11 | 10 0.456 27.331 7.942 0.975 0.298 12 | 11 0.584 45.000 6.078 0.902 0.431 13 | 12 0.545 34.728 6.547 0.993 0.376 14 | 13 0.774 23.431 3.303 0.898 0.680 15 | 15 0.776 18.493 2.467 0.842 0.720 16 | 17 0.739 27.166 3.424 0.952 0.605 17 | 18 0.823 16.155 1.971 0.923 0.743 18 | 19 0.475 19.209 4.078 0.605 0.391 19 | 20 0.848 6.708 1.865 0.801 0.901 20 | 21 0.637 87.207 7.408 0.650 0.625 21 | 22 0.334 21.213 6.414 0.269 0.441 22 | 23 0.435 31.321 5.128 0.956 0.281 23 | 25 0.657 28.302 3.099 0.757 0.580 24 | 26 0.687 21.000 3.059 0.560 0.889 25 | 28 0.796 27.821 3.019 0.838 0.758 26 | 29 0.748 31.321 3.187 0.783 0.715 27 | 30 0.301 28.460 6.877 0.966 0.178 28 | 31 0.413 32.450 5.598 0.864 0.271 29 | 32 0.557 61.262 7.348 0.732 0.449 30 | 33 0.667 21.000 3.746 0.717 0.623 31 | 34 0.248 82.104 19.367 0.142 0.971 32 | 35 0.658 19.209 4.503 0.981 0.495 33 | 36 0.854 14.071 1.984 0.839 0.869 34 | 37 0.000 54.663 45.042 0.000 0.000 35 | 39 0.000 inf inf 0.000 0.000 36 | 40 0.357 48.929 9.338 0.995 0.217 37 | 41 0.000 81.277 47.814 0.000 0.000 38 | 42 0.664 21.213 2.952 0.924 0.519 39 | 43 0.679 16.432 4.177 0.971 0.522 40 | 44 0.000 inf inf 0.000 0.000 41 | 45 0.391 78.345 16.282 0.315 0.516 42 | WARNING: Average values only computed on 36 of 38 cases! 43 | DM average 0.567611751082 +/- 0.212670241403 (Median: 0.647079809342) 44 | HD average 35.176100596 +/- 22.2798551804 (Median: 28.0613994413) 45 | ASSD average 8.02359553405 +/- 10.0398144431 (Median: 4.81560203066) 46 | Prec. average 0.764347212196 +/- 0.277209475282 (Median: 0.880709807434) 47 | Rec. average 0.515556132438 +/- 0.236903997964 (Median: 0.520182021822) 48 | 49 | ExtraTrees 50 | Flair only, all features 51 | bootstrap=true 52 | max_features=auto 53 | 54 | For comparison: Old, piece-wise intensity standardization 55 | INFO: Compute overall evaluation 56 | Metrics: 57 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 58 | 03 0.586 36.000 7.583 0.978 0.418 59 | 04 0.717 63.569 6.539 0.700 0.735 60 | 05 0.377 34.467 10.805 0.999 0.232 61 | 06 0.783 21.000 3.209 0.960 0.661 62 | 07 0.858 12.728 2.191 0.941 0.788 63 | 08 0.680 27.000 5.766 0.980 0.521 64 | 09 0.708 10.392 2.009 0.798 0.637 65 | 10 0.475 31.177 7.595 0.980 0.313 66 | 11 0.508 43.370 6.340 0.964 0.345 67 | 12 0.818 21.000 2.761 0.966 0.709 68 | 13 0.811 24.920 2.938 0.914 0.729 69 | 15 0.779 15.297 2.375 0.828 0.736 70 | 17 0.801 16.432 2.898 0.765 0.840 71 | 18 0.725 15.297 2.819 0.943 0.588 72 | 19 0.547 18.493 4.141 0.582 0.516 73 | 20 0.874 8.485 1.487 0.885 0.864 74 | 21 0.819 17.234 2.380 0.922 0.737 75 | 22 0.220 33.136 8.817 0.166 0.325 76 | 23 0.467 36.249 7.670 0.551 0.404 77 | 25 0.615 22.045 3.540 0.516 0.761 78 | 26 0.690 18.493 3.197 0.561 0.896 79 | 28 0.822 27.821 2.769 0.849 0.797 80 | 29 0.720 42.532 4.146 0.832 0.634 81 | 30 0.519 29.547 6.528 0.940 0.358 82 | 31 0.601 30.150 4.361 0.858 0.462 83 | 32 0.593 62.642 7.001 0.618 0.570 84 | 33 0.560 20.125 4.543 0.974 0.393 85 | 34 0.817 12.728 1.768 0.874 0.767 86 | 35 0.811 15.297 2.849 0.957 0.703 87 | 36 0.853 13.748 2.102 0.819 0.891 88 | 37 0.000 72.062 50.015 0.000 0.000 89 | 39 0.672 10.817 2.104 0.704 0.643 90 | 40 0.344 45.497 8.895 0.971 0.209 91 | 41 0.087 52.048 12.991 1.000 0.046 92 | 42 0.469 82.158 15.075 0.570 0.398 93 | 43 0.696 17.234 4.143 0.951 0.549 94 | 44 0.000 inf inf 0.000 0.000 95 | 45 0.400 31.890 7.894 0.431 0.372 96 | WARNING: Average values only computed on 37 of 38 cases! 97 | DM average 0.616716618646 +/- 0.211841539491 (Median: 0.680055401662) 98 | HD average 29.5427329711 +/- 17.7888488895 (Median: 24.9198715888) 99 | ASSD average 6.33089003315 +/- 7.95133868259 (Median: 4.1434107242) 100 | Prec. average 0.790482744681 +/- 0.232481698698 (Median: 0.873563218391) 101 | Rec. average 0.555311262885 +/- 0.22875838009 (Median: 0.588452088452) 102 | 103 | -------------------------------------------------------------------------------- /logs/eval.all.momentnormalization.log~: -------------------------------------------------------------------------------- 1 | INFO: Compute overall evaluation 2 | Metrics: 3 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 4 | 03 0.693 30.150 5.655 0.952 0.545 5 | 04 0.722 81.884 9.996 0.680 0.769 6 | 05 0.409 50.646 11.163 0.959 0.260 7 | 06 0.707 21.213 4.196 0.965 0.558 8 | 07 0.756 12.728 3.357 0.915 0.644 9 | 08 0.543 30.150 7.544 0.973 0.377 10 | 09 0.501 13.748 2.923 0.922 0.344 11 | 10 0.456 27.331 7.942 0.975 0.298 12 | 11 0.584 45.000 6.078 0.902 0.431 13 | 12 0.545 34.728 6.547 0.993 0.376 14 | 13 0.774 23.431 3.303 0.898 0.680 15 | 15 0.776 18.493 2.467 0.842 0.720 16 | 17 0.739 27.166 3.424 0.952 0.605 17 | 18 0.823 16.155 1.971 0.923 0.743 18 | 19 0.475 19.209 4.078 0.605 0.391 19 | 20 0.848 6.708 1.865 0.801 0.901 20 | 21 0.637 87.207 7.408 0.650 0.625 21 | 22 0.334 21.213 6.414 0.269 0.441 22 | 23 0.435 31.321 5.128 0.956 0.281 23 | 25 0.657 28.302 3.099 0.757 0.580 24 | 26 0.687 21.000 3.059 0.560 0.889 25 | 28 0.796 27.821 3.019 0.838 0.758 26 | 29 0.748 31.321 3.187 0.783 0.715 27 | 30 0.301 28.460 6.877 0.966 0.178 28 | 31 0.413 32.450 5.598 0.864 0.271 29 | 32 0.557 61.262 7.348 0.732 0.449 30 | 33 0.667 21.000 3.746 0.717 0.623 31 | 34 0.248 82.104 19.367 0.142 0.971 32 | 35 0.658 19.209 4.503 0.981 0.495 33 | 36 0.854 14.071 1.984 0.839 0.869 34 | 37 0.000 54.663 45.042 0.000 0.000 35 | 39 0.000 inf inf 0.000 0.000 36 | 40 0.357 48.929 9.338 0.995 0.217 37 | 41 0.000 81.277 47.814 0.000 0.000 38 | 42 0.664 21.213 2.952 0.924 0.519 39 | 43 0.679 16.432 4.177 0.971 0.522 40 | 44 0.000 inf inf 0.000 0.000 41 | 45 0.391 78.345 16.282 0.315 0.516 42 | WARNING: Average values only computed on 36 of 38 cases! 43 | DM average 0.567611751082 +/- 0.212670241403 (Median: 0.647079809342) 44 | HD average 35.176100596 +/- 22.2798551804 (Median: 28.0613994413) 45 | ASSD average 8.02359553405 +/- 10.0398144431 (Median: 4.81560203066) 46 | Prec. average 0.764347212196 +/- 0.277209475282 (Median: 0.880709807434) 47 | Rec. average 0.515556132438 +/- 0.236903997964 (Median: 0.520182021822) 48 | 49 | ExtraTrees 50 | Flair only, all features 51 | bootstrap=true 52 | max_features=auto 53 | 54 | For comparison: Old, piece-wise intensity standardization 55 | INFO: Compute overall evaluation 56 | Metrics: 57 | Case DC[0,1] HD(mm) P2C(mm) prec. recall 58 | 03 0.586 36.000 7.583 0.978 0.418 59 | 04 0.717 63.569 6.539 0.700 0.735 60 | 05 0.377 34.467 10.805 0.999 0.232 61 | 06 0.783 21.000 3.209 0.960 0.661 62 | 07 0.858 12.728 2.191 0.941 0.788 63 | 08 0.680 27.000 5.766 0.980 0.521 64 | 09 0.708 10.392 2.009 0.798 0.637 65 | 10 0.475 31.177 7.595 0.980 0.313 66 | 11 0.508 43.370 6.340 0.964 0.345 67 | 12 0.818 21.000 2.761 0.966 0.709 68 | 13 0.811 24.920 2.938 0.914 0.729 69 | 15 0.779 15.297 2.375 0.828 0.736 70 | 17 0.801 16.432 2.898 0.765 0.840 71 | 18 0.725 15.297 2.819 0.943 0.588 72 | 19 0.547 18.493 4.141 0.582 0.516 73 | 20 0.874 8.485 1.487 0.885 0.864 74 | 21 0.819 17.234 2.380 0.922 0.737 75 | 22 0.220 33.136 8.817 0.166 0.325 76 | 23 0.467 36.249 7.670 0.551 0.404 77 | 25 0.615 22.045 3.540 0.516 0.761 78 | 26 0.690 18.493 3.197 0.561 0.896 79 | 28 0.822 27.821 2.769 0.849 0.797 80 | 29 0.720 42.532 4.146 0.832 0.634 81 | 30 0.519 29.547 6.528 0.940 0.358 82 | 31 0.601 30.150 4.361 0.858 0.462 83 | 32 0.593 62.642 7.001 0.618 0.570 84 | 33 0.560 20.125 4.543 0.974 0.393 85 | 34 0.817 12.728 1.768 0.874 0.767 86 | 35 0.811 15.297 2.849 0.957 0.703 87 | 36 0.853 13.748 2.102 0.819 0.891 88 | 37 0.000 72.062 50.015 0.000 0.000 89 | 39 0.672 10.817 2.104 0.704 0.643 90 | 40 0.344 45.497 8.895 0.971 0.209 91 | 41 0.087 52.048 12.991 1.000 0.046 92 | 42 0.469 82.158 15.075 0.570 0.398 93 | 43 0.696 17.234 4.143 0.951 0.549 94 | 44 0.000 inf inf 0.000 0.000 95 | 45 0.400 31.890 7.894 0.431 0.372 96 | WARNING: Average values only computed on 37 of 38 cases! 97 | DM average 0.616716618646 +/- 0.211841539491 (Median: 0.680055401662) 98 | HD average 29.5427329711 +/- 17.7888488895 (Median: 24.9198715888) 99 | ASSD average 6.33089003315 +/- 7.95133868259 (Median: 4.1434107242) 100 | Prec. average 0.790482744681 +/- 0.232481698698 (Median: 0.873563218391) 101 | Rec. average 0.555311262885 +/- 0.22875838009 (Median: 0.588452088452) 102 | 103 | -------------------------------------------------------------------------------- /pop_original.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ##### 4 | # Link images from the image database in a consitent manner to 00originals. 5 | # Links all images whose case ids are mentiones in "includes.sh". 6 | # Flips every second case mid-saggital to have some right-sided lesions. 7 | ##### 8 | 9 | ## Changelog 10 | # 2014-05-05 every second case now gets flipped 11 | # 2014-03-24 changed to link sequence by availability (i.e. skip non-existing ones with only info message displayed) 12 | # 2013-11-13 changed to actually copy even existing files and to correct the qform and sform codes 13 | # 2013-10-15 changed the ADC creation script and added a conversion of non-float to float images 14 | # 2013-10-02 created 15 | 16 | # include shared information 17 | source $(dirname $0)/include.sh 18 | 19 | # Constants 20 | sequencestolink=('flair_tra' 'dw_tra_b1000_dmean' 'adc_tra' 't1_tra_ffe' 't1_sag_tfe' 't2_sag_tse' 't2_tra_ffe' 't2_tra_tse') # where available / saggital dims = 0, 0, 0, 0, 2, 2, 0, 0 21 | declare -A sequencesflipdims=( ['flair_tra']="0" ['dw_tra_b1000_dmean']="0" ['adc_tra']="0" ['t1_tra_ffe']="0" \ 22 | ['t1_sag_tfe']="2" ['t2_sag_tse']="2" ['t2_tra_ffe']="0" ['t2_tra_tse']="0" ) 23 | 24 | 25 | # Image collection HEOPKS details 26 | c01dir="/imagedata/HEOPKS/data/" 27 | declare -A c01indicesmapping=( ["01"]="01" ["02"]="02" ["03"]="03" ["04"]="04" ["05"]="05" ["06"]="06" ["07"]="07" ["08"]="08" ["09"]="09" ["10"]="10" \ 28 | ["11"]="11" ["12"]="12" ["13"]="13" ["14"]="14" ["15"]="15" ["16"]="16" ["17"]="17" ["18"]="18" ["19"]="19" ["20"]="20" \ 29 | ["21"]="21" ["22"]="22" ["23"]="23" ["24"]="24" ["25"]="25" ["26"]="26" ["27"]="27" ["28"]="28" ["29"]="29" ) 30 | 31 | # Image collection JGABLENTZ details 32 | c02dir="/imagedata/JGABLENTZ/data/" 33 | declare -A c02indicesmapping=( ["30"]="02" ["31"]="08" ["32"]="11" ["33"]="13" ["34"]="14" ["35"]="17" ["36"]="19" ["37"]="20" ["38"]="25" ["39"]="29" \ 34 | ["40"]="30" ["41"]="31" ["42"]="34" ["43"]="47" ["44"]="55" ["45"]="57" ) 35 | 36 | 37 | # functions 38 | ### 39 | # Create an ADC map if required sequences are available 40 | ### 41 | function make_adc_map () { 42 | srcdir=$1 43 | trgfile=$2 44 | 45 | if [ -f "${srcdir}/dw_tra_b0_dmean.${imgfiletype}" ]; then 46 | if [ -f "${srcdir}/dw_tra_b1000_dmean.${imgfiletype}" ]; then 47 | log 1 "Computing ADC map ${trgfile} with b=1000" "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 48 | runcond "medpy_apparent_diffusion_coefficient.py ${srcdir}/dw_tra_b0_dmean.${imgfiletype} ${srcdir}/dw_tra_b1000_dmean.${imgfiletype} 1000 ${trgfile}" 49 | elif [ -f "${srcdir}/dw_tra_b3000_dmean.${imgfiletype}" ]; then 50 | log 1 "Computing ADC map ${trgfile} with b=3000" "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 51 | runcond "medpy_apparent_diffusion_coefficient.py ${srcdir}/dw_tra_b0_dmean.${imgfiletype} ${srcdir}/dw_tra_b3000_dmean.${imgfiletype} 3000 ${trgfile}" 52 | fi 53 | fi 54 | } 55 | 56 | ### 57 | # Link all the sequences of a case 58 | ### 59 | function link_case () { 60 | 61 | srcdir=$1 62 | idx=$2 63 | 64 | log 2 "Linking case ${idx} from ${srcdir}" "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 65 | mkdircond "${originals}/${idx}" 66 | 67 | for s in "${sequencestolink[@]}"; do 68 | srcfile="${srcdir}/${s}.${imgfiletype}" 69 | trgfile="${originals}/${idx}/${s}.${imgfiletype}" 70 | 71 | # continue if target file already exists 72 | if [ -f "${trgfile}" ]; then 73 | log 1 "Target file ${trgfile} already exists. Skipping." "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 74 | continue 75 | fi 76 | 77 | # if source file exists 78 | if [ -f "${srcfile}" ]; then 79 | log 1 "Copying, to float62 and metadata correction for ${srcfile} to ${trgfile}" "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 80 | # copy and convert datatype to float64 81 | runcond "${scripts}/tofloat64.py ${srcfile} ${trgfile}" 82 | # correct nifit orientation metadata in-place 83 | runcond "${scripts}/niftimodifymetadata.py ${trgfile} qf=aff sf=aff qfc=1 sfc=1" 84 | elif [ "${s}" == "adc_tra" ]; then # compute ADC map if possible 85 | make_adc_map "${srcdir}" "${trgfile}" 86 | if [ ! -f "${trgfile}" ]; then 87 | log 1 "No sequence ${s} found for this case" "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 88 | fi 89 | else 90 | log 1 "No sequence ${s} found for this case" "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 91 | fi 92 | done 93 | } 94 | 95 | # main code 96 | log 2 "Copying / converting images and correcting metadata" "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 97 | for i in "${images[@]}"; do 98 | if test "${c01indicesmapping[${i}]+isset}"; then 99 | link_case "${c01dir}/${c01indicesmapping[${i}]}" "${i}" 100 | elif test "${c02indicesmapping[${i}]+isset}"; then 101 | link_case "${c02dir}/${c02indicesmapping[${i}]}" "${i}" 102 | else 103 | log 3 "No candidate for case id ${i} found in any of the collections. Please check your 'images' array. Skipping." "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 104 | fi 105 | done 106 | 107 | log 2 "Flipping images of every second case in-place along the mid-saggital plane" "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 108 | for (( i = 1 ; i < ${#images[@]} ; i+=2 )) do 109 | for s in "${sequencestolink[@]}"; do 110 | f="${originals}/${images[$i]}/${s}.${imgfiletype}" 111 | if [ -e ${f} ]; then 112 | lnrealize "${f}" 113 | runcond "${scripts}/flip.py ${f} ${sequencesflipdims[${s}]}" 114 | fi 115 | done 116 | done 117 | 118 | log 2 "Done." "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 119 | 120 | -------------------------------------------------------------------------------- /pop_sequencespace.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ##### 4 | # Rigidly registers all sequences to a base sequence, which can optionally be resampled to isotropic spacing. 5 | ##### 6 | 7 | ## Changelog 8 | # 2014-03-24 Changed to a more flexible version 9 | # 2013-11-13 Added step to correct the qform and sform codes 10 | # 2013-11-04 Added re-sampling of T2 image to isotropic spacing before registration and updated loop design. 11 | # 2013-10-16 ADC images are now not registered directly, but rather transformed with the DW transformation matrix 12 | # 2013-10-15 created 13 | 14 | # include shared information 15 | source $(dirname $0)/include.sh 16 | 17 | # functions 18 | ### 19 | # Resample the base sequence of the supplied id 20 | ### 21 | function resample () 22 | { 23 | idx=$1 24 | 25 | srcfile="${originals}/${idx}/${basesequence}.${imgfiletype}" 26 | trgfile="${sequencespace}/${idx}/${basesequence}.${imgfiletype}" 27 | 28 | mkdircond ${sequencespace}/${idx} 29 | 30 | # warn and skip if source file not present 31 | if [ ! -f "${srcfile}" ]; then 32 | log 3 "Base sequence for case ${idx} not found under ${srcfile}. Skipping." "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 33 | return 34 | fi 35 | 36 | # process if target file not yet existing 37 | if [ ! -f "${trgfile}" ]; then 38 | log 1 "Isotropic resampling to ${trgfile}" "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 39 | runcond "medpy_resample.py ${srcfile} ${trgfile} ${isotropicspacing},${isotropicspacing},${isotropicspacing}" 40 | fi 41 | } 42 | 43 | ### 44 | # Register an image to another, also saving the transformation matrix. 45 | ### 46 | function register () 47 | { 48 | idx=$1 49 | sequence=$2 50 | 51 | trgdir="${sequencespace}/${idx}/" 52 | fixed="${trgdir}/${basesequence}.${imgfiletype}" 53 | moving="${originals}/${idx}/${sequence}.${imgfiletype}" 54 | 55 | tmpdir=`mktemp -d` 56 | 57 | # perform rigid registration 58 | log 1 "Registering ${moving} to ${fixed} using tmp dir ${tmpdir}" 59 | runcond "elastix -f ${fixed} -m ${moving} -out ${tmpdir} -p ${configs}/elastix_sequencespace_rigid_cfg.txt -threads=${threadcount}" /dev/null 60 | # copy resulting files 61 | cpcond "${tmpdir}/result.0.nii.gz" "${trgdir}/${sequence}.${imgfiletype}" 62 | cpcond "${tmpdir}/TransformParameters.0.txt" "${trgdir}/${sequence}.txt" 63 | 64 | # clean up 65 | emptydircond "${tmpdir}" 66 | rmdircond "${tmpdir}" 67 | } 68 | 69 | ### 70 | # Tranform a sequence using an already existing transformation matrix 71 | ### 72 | function transform () 73 | { 74 | idx=$1 75 | sequence=$2 76 | matrix=$3 77 | 78 | trgdir="${sequencespace}/${idx}/" 79 | moving="${originals}/${sequence}.${imgfiletype}" 80 | 81 | tmpdir=`mktemp -d` 82 | 83 | # perform transformation 84 | log 1 "Transforming ${sequence} image ${moving} with ${matrix} transformation matrix using tmp dir ${tmpdir}" 85 | runcond "transformix -in ${originals}/${i}/adc_tra.${imgfiletype} -out ${tmpdir} -tp ${matrix}" /dev/null 86 | # copy resulting file 87 | cpcond "${tmpdir}/result.nii.gz" "${trgdir}/${sequence}.${imgfiletype}" 88 | cpcond "${matrix}" "${trgdir}/${sequence}.txt" 89 | 90 | # clean up 91 | emptydircond ${tmpdir} 92 | rmdircond "${tmpdir}" 93 | } 94 | 95 | 96 | # main code 97 | if (( $isotropic == 1 )) ; then 98 | log 2 "Resampling all ${basesequence} sequences to isotropic spacing of ${isotropicspacing}mm" "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 99 | parallelize resample ${threadcount} images[@] 100 | else 101 | log 2 "Resampling disabled. Linking base sequences ${basesequence} to target folder." "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 102 | for i in "${images[@]}"; do 103 | mkdircond ${sequencespace}/${i} 104 | lncond "${PWD}/${originals}/${i}/${basesequence}.${imgfiletype}" "${sequencespace}/${i}/${basesequence}.${imgfiletype}" 105 | done 106 | fi 107 | 108 | log 2 "Registering all remaining sequences to the base sequence ${basesequence}" "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 109 | for i in "${images[@]}"; do 110 | for s in "${sequences[@]}"; do 111 | srcfile="${originals}/${i}/${s}.${imgfiletype}" 112 | trgfile="${sequencespace}/${i}/${s}.${imgfiletype}" 113 | 114 | # catch base sequence and continue, since it is the fixed image and does not need registration 115 | if [ "${s}" == "${basesequence}" ]; then 116 | continue 117 | fi 118 | # catch ADC and continue, since these are transformed with the DW transformation matrices 119 | if [ "${s}" == "adc_tra" ]; then 120 | continue 121 | fi 122 | # continue if target file already exists 123 | if [ -f "${trgfile}" ]; then 124 | continue 125 | fi 126 | # warn if source file does not exist 127 | if [ ! -f "${srcfile}" ]; then 128 | log 3 "The source file ${srcfile} does not exist. Skipping." "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 129 | continue 130 | fi 131 | 132 | # perform rigid registration 133 | register "${i}" "${s}" 134 | done 135 | done 136 | 137 | if isIn "adc_tra" "${sequences[@]}"; then 138 | log 2 "Registering resp. transforming ADC images" "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 139 | for i in "${images[@]}"; do 140 | srcfile="${originals}/${i}/adc_tra.${imgfiletype}" 141 | trgfile="${sequencespace}/${i}/adc_tra.${imgfiletype}" 142 | matrix="${sequencespace}/${i}/dw_tra_b1000_dmean.txt" 143 | 144 | # warn if source file does not exist 145 | if [ ! -f "${srcfile}" ]; then 146 | log 3 "The source file ${srcfile} does not exist. Skipping." "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 147 | continue 148 | fi 149 | # continue if target file already exists 150 | if [ -f "${trgfile}" ]; then 151 | continue 152 | fi 153 | 154 | # transform if an DW image has already been registered 155 | if [ -f "${matrix}" ]; then 156 | transform "${i}" "adc_tra" "${matrix}" 157 | else 158 | register "${i}" "adc_tra" 159 | fi 160 | done 161 | fi 162 | 163 | log 2 "Correcting metadata" "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 164 | for i in "${images[@]}"; do 165 | for s in "${sequences[@]}"; do 166 | if [ -f "${sequencespace}/${i}/${s}.${imgfiletype}" ]; then 167 | runcond "${scripts}/niftimodifymetadata.py ${sequencespace}/${i}/${s}.${imgfiletype} qf=qf sf=qf qfc=1 sfc=1" 168 | fi 169 | done 170 | done 171 | 172 | log 2 "Done." "[$BASH_SOURCE:$FUNCNAME:$LINENO]" 173 | 174 | -------------------------------------------------------------------------------- /scripts/parse_excluding.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | """ 4 | Parses an evaluation result produced by evaluate.sh resp. 5 | evaluate_original.sh and converts it into csv or latex conform 6 | output. Output is written to stdout. 7 | """ 8 | 9 | # build-in modules 10 | import argparse 11 | import logging 12 | import sys 13 | 14 | # third-party modules 15 | import numpy 16 | 17 | # path changes 18 | 19 | # own modules 20 | from medpy.core import Logger 21 | from medpy.io import load, save 22 | 23 | # information 24 | __author__ = "Oskar Maier" 25 | __version__ = "r0.1.0, 2014-06-10" 26 | __email__ = "oskar.maier@googlemail.com" 27 | __status__ = "Release" 28 | __description__ = """ 29 | Parses an evaluation file under the exclusion of some selected cases. 30 | 31 | Copyright (C) 2013 Oskar Maier 32 | This program comes with ABSOLUTELY NO WARRANTY; This is free software, 33 | and you are welcome to redistribute it under certain conditions; see 34 | the LICENSE file or for details. 35 | """ 36 | 37 | # code 38 | def main(): 39 | args = getArguments(getParser()) 40 | 41 | # prepare logger 42 | logger = Logger.getInstance() 43 | if args.debug: logger.setLevel(logging.DEBUG) 44 | elif args.verbose: logger.setLevel(logging.INFO) 45 | 46 | # prepare arguments 47 | excluded_cases = sys.argv[2:] 48 | 49 | # parse evaluation file 50 | eva = Evaluation() 51 | eva.parse(args.input, excluded_cases) 52 | print 'Parsed a total of {} cases after the exclusion of {}.'.format(eva.case_count(-1), excluded_cases) 53 | print 'DC', eva.mean('DC[0,1]', -1) 54 | print 'HD', eva.mean('HD(mm)', -1) 55 | print 'ASSD', eva.mean('P2C(mm)', -1) 56 | print 'Prec.', eva.mean('prec.', -1) 57 | print 'Recall', eva.mean('recall', -1) 58 | 59 | logger.info("Successfully terminated.") 60 | 61 | class Evaluation: 62 | """ 63 | Object constructed from an evaluation file. 64 | Call parse() method to initialize. 65 | """ 66 | def __init__(self): 67 | self.logger = Logger.getInstance() 68 | self.headers = [] 69 | self.results = [] 70 | self.parsed = False 71 | 72 | def parse(self, file_name, exluded_cases = []): 73 | """Parse an evaluation file and initialize the object excluding the given cases.""" 74 | # check if already parsed 75 | if self.parsed: 76 | raise Exception("Can only parse once, please initialize another Evaluation object.") 77 | 78 | # prepare signals and counters 79 | inside_evaluation_block = False 80 | inside_summary_block = False 81 | evaluation_blocks_encountered = 0 82 | 83 | # parse evaluation file 84 | self.logger.info("Parsing evaluation file {}.".format(file_name)) 85 | with open(file_name, 'r') as f: 86 | for line in f.readlines(): 87 | line = line.strip() 88 | if inside_evaluation_block: 89 | if 'WARNING' in line: # skip warnings 90 | continue 91 | elif 'average' in line: # stop condition approaching 92 | inside_summary_block = True 93 | elif inside_summary_block: # stop condition reached 94 | inside_evaluation_block = False 95 | inside_summary_block = False 96 | evaluation_blocks_encountered +=1 97 | self.logger.debug("Parsing of evaluation block terminated.") 98 | self.headers.append(header) 99 | self.results.append(result) 100 | else: # normal case evaluation line 101 | chunks = map(lambda x: x.strip(), line.split()) 102 | if not chunks[0] in exluded_cases: 103 | result[chunks[0]] = map(float, chunks[1:]) 104 | elif "Case" == line[:4]: # start condition 105 | inside_evaluation_block = True 106 | self.logger.debug("Evaluation block no. {} found.".format(evaluation_blocks_encountered + 1)) 107 | header = map(lambda x: x.strip(), line.split())[1:] 108 | result = dict() 109 | if inside_summary_block: # stop condition reached 110 | inside_evaluation_block = False 111 | inside_summary_block = False 112 | evaluation_blocks_encountered +=1 113 | self.logger.debug("Parsing of evaluation block terminated.") 114 | self.headers.append(header) 115 | self.results.append(result) 116 | 117 | # set stated to parsed 118 | self.parsed = True 119 | 120 | def evaluation_block_count(self): 121 | return len(self.headers) 122 | 123 | def case_count(self, evaluation_block = 0): 124 | return len(self.results[evaluation_block]) 125 | 126 | def header_count(self, evaluation_block = 0): 127 | return len(self.headers[evaluation_block]) 128 | 129 | def headers(self, evaluation_block = 0): 130 | return self.headers[evaluation_block] 131 | 132 | def results(self, evaluation_block = 0): 133 | return self.results[evaluation_block] 134 | 135 | def mean(self, metric, evaluation_block = 0): 136 | return numpy.mean(self.__get_metric(metric, evaluation_block)) 137 | 138 | def median(self, metric, evaluation_block = 0): 139 | return numpy.median(self.__get_metric(metric, evaluation_block)) 140 | 141 | def std(self, metric, evaluation_block = 0): 142 | return numpy.std(self.__get_metric(metric, evaluation_block)) 143 | 144 | def __get_metric(self, metric, evaluation_block = 0): 145 | if not self.__is_int(metric): 146 | metric = self.headers[evaluation_block].index(metric) 147 | return [x[metric] for x in self.results[evaluation_block].values()] 148 | 149 | def __is_int(self, s): 150 | try: 151 | int(s) 152 | return True 153 | except ValueError: 154 | return False 155 | 156 | def getArguments(parser): 157 | "Provides additional validation of the arguments collected by argparse." 158 | return parser.parse_args() 159 | 160 | def getParser(): 161 | "Creates and returns the argparse parser object." 162 | parser = argparse.ArgumentParser(description=__description__) 163 | parser.add_argument('input', help='The evaluation file to parse.') 164 | parser.add_argument('cases', nargs='+', help='The cases to exclude.') 165 | parser.add_argument('-v', dest='verbose', action='store_true', help='Display more information.') 166 | parser.add_argument('-d', dest='debug', action='store_true', help='Display debug information.') 167 | return parser 168 | 169 | if __name__ == "__main__": 170 | main() 171 | --------------------------------------------------------------------------------