From e3b84db978c2698d48853c27bc97073320b83afc Mon Sep 17 00:00:00 2001 From: Stefan Date: Mon, 5 Sep 2022 11:16:50 +0200 Subject: [PATCH] changes after several weeks --- scripts/1.U-net_chris.py | 4 +- scripts/11.visualize_multiple_frocs.py | 59 ++++-- scripts/13.froc_umcglib.py | 192 +++++++++++++++++ scripts/14.saliency.py | 149 +++++++++++++ scripts/15.plot_paper_graphs.py | 34 +++ scripts/16.plot_paper_saliency.py | 89 ++++++++ scripts/17.plot_paper_adc_diff.py | 92 ++++++++ scripts/18.build_db.py | 254 +++++++++++++++++++++++ scripts/19.clinical_variables.py | 134 ++++++++++++ scripts/4.frocs.py | 40 +--- scripts/7.Visualize_saliency.py | 15 +- scripts/calc_adc_b1400.py | 38 ++-- scripts/heatmap_result_1.png | Bin 0 -> 94142 bytes scripts/miccai_rss_recon_undersampled.py | 2 +- scripts/test.py | 198 ++++++++++-------- scripts/test2.py | 64 ++++++ 16 files changed, 1204 insertions(+), 160 deletions(-) create mode 100755 scripts/13.froc_umcglib.py create mode 100755 scripts/14.saliency.py create mode 100755 scripts/15.plot_paper_graphs.py create mode 100755 scripts/16.plot_paper_saliency.py create mode 100755 scripts/17.plot_paper_adc_diff.py create mode 100755 scripts/18.build_db.py create mode 100755 scripts/19.clinical_variables.py create mode 100644 scripts/heatmap_result_1.png create mode 100755 scripts/test2.py diff --git a/scripts/1.U-net_chris.py b/scripts/1.U-net_chris.py index 0bff473..9ba4c20 100755 --- a/scripts/1.U-net_chris.py +++ b/scripts/1.U-net_chris.py @@ -29,6 +29,8 @@ from sfransen.DWI_exp.batchgenerator import BatchGenerator from sfransen.DWI_exp.unet import build_dual_attention_unet from focal_loss import BinaryFocalLoss +# from umcglib.utils import set_gpu +# set_gpu(gpu_idx=1) parser = argparse.ArgumentParser( description='Train a U-Net model for segmentation/detection tasks.' + @@ -125,7 +127,7 @@ with open(path.join(DATA_DIR, f"seg.txt"), 'r') as f: num_images = len(seg_paths) # Read and preprocess each of the paths for each series, and the segmentations. -for img_idx in tqdm(range(num_images)): #[:40]): #for less images +for img_idx in tqdm(range(num_images)): #[:20]): #for less images img_s = {s: sitk.ReadImage(image_paths[s][img_idx], sitk.sitkFloat32) for s in args.series} seg_s = sitk.ReadImage(seg_paths[img_idx], sitk.sitkFloat32) diff --git a/scripts/11.visualize_multiple_frocs.py b/scripts/11.visualize_multiple_frocs.py index 09111e4..6b4cd54 100755 --- a/scripts/11.visualize_multiple_frocs.py +++ b/scripts/11.visualize_multiple_frocs.py @@ -21,12 +21,13 @@ parser.add_argument('-yaml_metric', args = parser.parse_args() if args.comparison: - colors = ['r','r','b','b','g','g','y','y'] - plot_type = ['-','--','-','--','-','--','-','--'] + colors = ['b','c','r','m','g','g','y','y'] + plot_type = ['-','-','-','--','-','--','-','--'] else: - colors = ['r','b','k','g','c','y'] + colors = ['g','b','r','g','k','c','y'] plot_type = ['-','-','-','-','-','-'] + yaml_metric = args.yaml_metric experiments = args.experiment print(experiments) @@ -39,44 +40,53 @@ sensitivity = [] fig = plt.figure(1) ax = fig.add_subplot(111) -False_possitives_mean = np.linspace(0, 5, 200) +False_possitives_mean = np.linspace(0, 2.5, 200) for idx in range(len(args.experiment)): paufroc = [] - for fold in range(4): + experiment_path = [] + auroc = [] + paufroc = [] + False_possitives = [] + sensitivity = [] + for fold in range(5): # print('fold:',fold) - fold = fold + 1 experiment_metrics = {} experiment_path = f'./../train_output/{experiments[idx]}_{fold}/froc_metrics_{yaml_metric}.yml' experiment_metrics = read_yaml_to_dict(experiment_path) - pfroc = partial_auc(experiment_metrics["sensitivity"],experiment_metrics["FP_per_case"],low=0.1, high=5) + pfroc = partial_auc(experiment_metrics["sensitivity"],experiment_metrics["FP_per_case"],low=0.1, high=2.5) paufroc.append(round(pfroc,2)) False_possitives.append(experiment_metrics["FP_per_case"]) sensitivity_ = np.interp(False_possitives_mean,experiment_metrics["FP_per_case"],experiment_metrics["sensitivity"]) sensitivity.append(sensitivity_) + print(f'pfROC van {experiments[idx]}: {paufroc}') # calculate mean and std sensitivity_mean = np.squeeze(np.mean(sensitivity,axis=0)) sensitivity_std = np.multiply(np.squeeze(np.std(sensitivity,axis=0)),2) plt.plot(False_possitives_mean, sensitivity_mean,color=colors[idx],linestyle=plot_type[idx]) - plt.fill_between(False_possitives_mean, np.subtract(sensitivity_mean,sensitivity_std), np.add(sensitivity_mean,sensitivity_std),alpha=0.15,color=colors[idx],) + plt.fill_between(False_possitives_mean, np.subtract(sensitivity_mean,sensitivity_std), np.add(sensitivity_mean,sensitivity_std),alpha=0.10,color=colors[idx],) ax.set(xscale="log") ax.axes.xaxis.set_minor_locator(tkr.LogLocator(base=10, subs='all')) ax.axes.xaxis.set_minor_formatter(tkr.NullFormatter()) ax.axes.xaxis.set_major_formatter(tkr.ScalarFormatter()) - ax.axes.grid(True, which="both", ls="--", c='#d3d3d3') - ax.axes.set_xlim(left=0.1, right=5) - ax.axes.xaxis.set_major_locator(tkr.FixedLocator([0.1,0.5,1,5])) + ax.axes.get_xaxis() + ax.axes.get_yaxis() + ax.axes.set_xlim(left=0.1, right=2.5) + ax.axes.xaxis.set_major_locator(tkr.FixedLocator([0.1,0.5,1,2.5])) fpr = [] tpr = [] fpr_mean = np.linspace(0, 1, 200) for idx in range(len(args.experiment)): + aufroc = [] + experiment_path = [] auroc = [] - for fold in range(4): - fold= fold + 1 + fpr = [] + tpr = [] + for fold in range(5): print('fold:',fold) experiment_metrics = {} experiment_path = f'./../train_output/{experiments[idx]}_{fold}/froc_metrics_{yaml_metric}.yml' @@ -92,7 +102,7 @@ for idx in range(len(args.experiment)): plt.figure(2) plt.plot(fpr_mean, tpr_mean,color=colors[idx],linestyle=plot_type[idx]) - plt.fill_between(fpr_mean, np.subtract(tpr_mean,tpr_std), np.add(tpr_mean,tpr_std),alpha=0.15,color=colors[idx],) + plt.fill_between(fpr_mean, np.subtract(tpr_mean,tpr_std), np.add(tpr_mean,tpr_std),alpha=0.10,color=colors[idx],) print(auroc) experiments = [exp.replace('train_10h_', '') for exp in experiments] @@ -104,11 +114,13 @@ concat_func = lambda x,y: x + " (" + str(y) + ")" experiments_paufroc = list(map(concat_func,experiments,paufroc)) # list the map function plt.figure(1) -plt.title('fROC curve') -plt.xlabel('False positive per case') -plt.ylabel('Sensitivity') +plt.title('fROC curve', fontsize=20) +plt.xlabel('False positive lesions', fontsize=18) +plt.ylabel('Sensitivity', fontsize=18) # plt.legend(experiments_paufroc,loc='lower right') -plt.legend(['calculated with b50-400','calculated with b50-800'],loc='lower right') +# plt.legend(['$T2_{tra}$ $ADC_{b50-b400}$ $b1400_{b50-b400}$','$T2_{tra}$ $ADC_{b50-b800}$ $b1400_{b50-b800}$','$T2_{tra}$ $ADC_{b50-b400-b800}$ $b1400_{b50-b400-b800}$'],loc='lower right') +# plt.legend(['$T2_{tra}$ $ADC_{b50-b400-b800}$ $b1400_{b50-b400-b800}$','$T2_{tra}$ b50 b400 b800'],loc='lower right') +plt.legend(["All b-values","Omitting b800","Omitting b400"],loc='lower right',fontsize=16) # plt.xlim([0,50]) plt.grid() @@ -120,11 +132,14 @@ concat_func = lambda x,y: x + " (" + str(y) + ")" experiments_auroc = list(map(concat_func,experiments,auroc)) # list the map function plt.figure(2) -plt.title('ROC curve') +plt.title('ROC curve',fontsize=20) # plt.legend(experiments_auroc,loc='lower right') -plt.legend(['calculated with b50-400','calculated with b50-800'],loc='lower right') -plt.xlabel('False positive rate') -plt.ylabel('True positive rate') +# plt.legend(['$T2_{tra}$ $ADC_{b50-b400-b800}$ $b1400_{b50-b400-b800}$','$T2_{tra}$ b50 b400 b800'],loc='lower right') +# plt.legend(['$T2_{tra}$ $ADC_{b50-b400}$ $b1400_{b50-b400}$','$T2_{tra}$ $ADC_{b50-b800}$ $b1400_{b50-b800}$','$T2_{tra}$ $ADC_{b50-b400-b800}$ $b1400_{b50-b400-b800}$'],loc='lower right') +plt.legend(["All b-values","Omitting b800","Omitting b400"],loc='lower right',fontsize=16) + +plt.xlabel('False positive rate',fontsize=18) +plt.ylabel('True positive rate',fontsize=18) plt.ylim([0,1]) plt.xlim([0,1]) plt.grid() diff --git a/scripts/13.froc_umcglib.py b/scripts/13.froc_umcglib.py new file mode 100755 index 0000000..aea3486 --- /dev/null +++ b/scripts/13.froc_umcglib.py @@ -0,0 +1,192 @@ +from inspect import _ParameterKind +import SimpleITK as sitk +import tensorflow as tf +from tensorflow.keras.models import load_model +from focal_loss import BinaryFocalLoss +import numpy as np +import multiprocessing +from functools import partial +import os +from os import path +from tqdm import tqdm +import argparse + +from sfransen.utils_quintin import * +from sfransen.DWI_exp.helpers import * +from sfransen.DWI_exp.preprocessing_function import preprocess +from sfransen.DWI_exp.callbacks import dice_coef +#from sfransen.FROC.blob_preprocess import * +from sfransen.FROC.cal_froc_from_np import * +from sfransen.load_images import load_images_parrallel +from sfransen.DWI_exp.losses import weighted_binary_cross_entropy +from umcglib.froc import * +from umcglib.binarize import dynamic_threshold + +parser = argparse.ArgumentParser( + description='Calculate the froc metrics and store in froc_metrics.yml') +parser.add_argument('-experiment', + help='Title of experiment') +parser.add_argument('--series', '-s', + metavar='[series_name]', required=True, nargs='+', + help='List of series to include') +parser.add_argument('-fold', + default='', + help='List of series to include') +args = parser.parse_args() + +# if __name__ = '__main__': +# bovenstaande nodig om fork probleem op te lossen (windows cs linux) + +######## CUDA ################ +os.environ["CUDA_VISIBLE_DEVICES"] = "2" + +######## constants ############# +SERIES = args.series +series_ = '_'.join(args.series) +EXPERIMENT = args.experiment +# fold = args.fold +predictions_added = [] +segmentations_added = [] + +for fold in range(0,5): + + MODEL_PATH = f'./../train_output/{EXPERIMENT}_{series_}_{fold}/models/{EXPERIMENT}_{series_}_{fold}.h5' + YAML_DIR = f'./../train_output/{EXPERIMENT}_{series_}_{fold}' + IMAGE_DIR = f'./../train_output/{EXPERIMENT}_{series_}_{fold}' + + # MODEL_PATH = f'./../train_output/{EXPERIMENT}_{series_}/models/{EXPERIMENT}_{series_}.h5' + # YAML_DIR = f'./../train_output/{EXPERIMENT}_{series_}' + # IMAGE_DIR = f'./../train_output/{EXPERIMENT}_{series_}' + + DATA_DIR = "./../data/Nijmegen paths/" + TARGET_SPACING = (0.5, 0.5, 3) + INPUT_SHAPE = (192, 192, 24, len(SERIES)) + IMAGE_SHAPE = INPUT_SHAPE[:3] + + DATA_SPLIT_INDEX = read_yaml_to_dict(f'./../data/Nijmegen paths/train_val_test_idxs_{fold}.yml') + # DATA_SPLIT_INDEX = read_yaml_to_dict(f'./../data/Nijmegen paths/train_val_test_idxs.yml') + TEST_INDEX = DATA_SPLIT_INDEX['test_set0'] + + N_CPUS = 12 + + + ########## test with old method ############# + print_(f"> Loading images into RAM...") + + image_paths = {} + + for s in SERIES: + with open(path.join(DATA_DIR, f"{s}.txt"), 'r') as f: + image_paths[s] = [l.strip() for l in f.readlines()] + with open(path.join(DATA_DIR, f"seg.txt"), 'r') as f: + seg_paths = [l.strip() for l in f.readlines()] + num_images = len(seg_paths) + + images = [] + images_list = [] + segmentations = [] + + # Read and preprocess each of the paths for each series, and the segmentations. + for img_idx in tqdm(range(len(TEST_INDEX))): #[:40]): #for less images + # print('images number',[TEST_INDEX[img_idx]]) + img_s = {f'{s}': sitk.ReadImage(image_paths[s][TEST_INDEX[img_idx]], sitk.sitkFloat32) for s in SERIES} + seg_s = sitk.ReadImage(seg_paths[TEST_INDEX[img_idx]], sitk.sitkFloat32) + img_n, seg_n = preprocess(img_s, seg_s, + shape=IMAGE_SHAPE, spacing=TARGET_SPACING) + for seq in img_n: + images.append(img_n[f'{seq}']) + images_list.append(images) + images = [] + segmentations.append(seg_n) + + images_list = np.transpose(images_list, (0, 2, 3, 4, 1)) + + print('>>>>> size image_list nmr 2:', np.shape(images_list), '. equal to: (5, 192, 192, 24, 3)?') + + ########### load module ################## + print(' >>>>>>> LOAD MODEL <<<<<<<<<') + + dependencies = { + 'dice_coef': dice_coef, + 'weighted_cross_entropy_fn':weighted_binary_cross_entropy + } + reconstructed_model = load_model(MODEL_PATH, custom_objects=dependencies) + # reconstructed_model.summary(line_length=120) + + # make predictions on all TEST_INDEX + print(' >>>>>>> START prediction <<<<<<<<<') + predictions_blur = reconstructed_model.predict(images_list, batch_size=1) + + ############# preprocess ################# + # preprocess predictions by removing the blur and making individual blobs + print('>>>>>>>> START preprocess') + + def move_dims(arr): + # UMCG numpy dimensions convention: dims = (batch, width, heigth, depth) + # Joeran numpy dimensions convention: dims = (batch, depth, heigth, width) + arr = np.moveaxis(arr, 3, 1) + arr = np.moveaxis(arr, 3, 2) + return arr + + # Joeran has his numpy arrays ordered differently. + predictions_blur = move_dims(np.squeeze(predictions_blur)) + segmentations = move_dims(np.squeeze(segmentations)) + # predictions = [preprocess_softmax(pred, threshold="dynamic")[0] for pred in predictions_blur] + predictions = predictions_blur + print("the size of predictions is:",np.shape(predictions)) + # Remove outer edges + zeros = np.zeros(np.shape(predictions)) + test = np.squeeze(predictions)[:,2:-2,2:190,2:190] + zeros[:,2:-2,2:190,2:190] = test + predictions = zeros + + # # perform Froc method joeran + # metrics = evaluate(y_true=segmentations, y_pred=predictions) + # dump_dict_to_yaml(metrics, YAML_DIR, "froc_metrics_focal_10_test", verbose=True) + + ############# save image as example ################# + # save image nmr 6 + # img_s = sitk.GetImageFromArray(predictions_blur[6].squeeze()) + # sitk.WriteImage(img_s, f"{IMAGE_DIR}/predictions_blur_006_dyn_0.6.nii.gz") + + # img_s = sitk.GetImageFromArray(predictions[6].squeeze()) + # sitk.WriteImage(img_s, f"{IMAGE_DIR}/predictions_006_dyn_0.6.nii.gz") + + # img_s = sitk.GetImageFromArray(segmentations[6].squeeze()) + # sitk.WriteImage(img_s, f"{IMAGE_DIR}/segmentations_006_dyn_0.6.nii.gz") + + # img_s = sitk.GetImageFromArray(np.transpose(images_list[6,:,:,:,0].squeeze())) + # sitk.WriteImage(img_s, f"{IMAGE_DIR}/t2_006_dyn_0.6.nii.gz") + + if fold == 0: + segmentations_added = segmentations + predictions_added = predictions + else: + segmentations_added = np.append(segmentations_added,segmentations,axis=0) + predictions_added = np.append(predictions_added,predictions,axis=0) + +# Froc method umcglib +stats = calculate_froc(y_true=segmentations_added, + y_pred=predictions_added, + preprocess_func=dynamic_threshold, + dynamic_threshold_factor=0.5, + minimum_confidence=0.1, + bootstrap = 1000, + min_overlap = 0.01, + overlap_function = 'dsc') + + +dump_stats_to_yaml(stats, YAML_DIR, "umcglib_stats_overlap_0.01", verbose=True) + +quit() +plot_multiple_froc( + sensitivities=[np.array(stats['sensitivity'])], + fp_per_patient=[np.array(stats["fp_per_patient"])], + ci_low=[np.array(stats['sens_95_boot_ci_low'])], + ci_high=[np.array(stats["sens_95_boot_ci_high"])], + model_names=["test only"], + title="testtest", + height=12, width=15, + save_as="froc_test_0.5_conf_0.1_overlap_0.1_dsc.png", + xlims=(0.1, 5) + ) \ No newline at end of file diff --git a/scripts/14.saliency.py b/scripts/14.saliency.py new file mode 100755 index 0000000..e51738d --- /dev/null +++ b/scripts/14.saliency.py @@ -0,0 +1,149 @@ +import argparse +from os import path +import SimpleITK as sitk +import tensorflow as tf +from tensorflow.keras.models import load_model +import numpy as np +import os + +from sfransen.utils_quintin import * +from sfransen.DWI_exp import preprocess +from sfransen.DWI_exp.helpers import * +from sfransen.DWI_exp.callbacks import dice_coef +from sfransen.DWI_exp.losses import weighted_binary_cross_entropy + +from sfransen.FROC.blob_preprocess import * +from sfransen.FROC.cal_froc_from_np import * +from sfransen.load_images import load_images_parrallel +from sfransen.Saliency.base import * +from sfransen.Saliency.integrated_gradients import * + +parser = argparse.ArgumentParser( + description='Calculate the froc metrics and store in froc_metrics.yml') +parser.add_argument('-experiment', + help='Title of experiment') +parser.add_argument('--series', '-s', + metavar='[series_name]', required=True, nargs='+', + help='List of series to include') +args = parser.parse_args() + +######## CUDA ################ +os.environ["CUDA_VISIBLE_DEVICES"] = "2" + +######## constants ############# +SERIES = args.series +series_ = '_'.join(args.series) +EXPERIMENT = args.experiment +fold = 0 +# img_idx = 371 +img_idx = 634 + + +predictions_added = [] +segmentations_added = [] + +MODEL_PATH = f'./../train_output/{EXPERIMENT}_{series_}_{fold}/models/{EXPERIMENT}_{series_}_{fold}.h5' +YAML_DIR = f'./../train_output/{EXPERIMENT}_{series_}_{fold}' +IMAGE_DIR = f'./../train_output/{EXPERIMENT}_{series_}_{fold}' + +# MODEL_PATH = f'./../train_output/{EXPERIMENT}_{series_}/models/{EXPERIMENT}_{series_}.h5' +# YAML_DIR = f'./../train_output/{EXPERIMENT}_{series_}' +# IMAGE_DIR = f'./../train_output/{EXPERIMENT}_{series_}' + +DATA_DIR = "./../data/Nijmegen paths/" +TARGET_SPACING = (0.5, 0.5, 3) +INPUT_SHAPE = (192, 192, 24, len(SERIES)) +IMAGE_SHAPE = INPUT_SHAPE[:3] + +DATA_SPLIT_INDEX = read_yaml_to_dict(f'./../data/Nijmegen paths/train_val_test_idxs_{fold}.yml') +TEST_INDEX = DATA_SPLIT_INDEX['test_set0'] + +N_CPUS = 12 + + +print(f"> Loading images into RAM...") + +image_paths = {} + +for s in SERIES: + with open(path.join(DATA_DIR, f"{s}.txt"), 'r') as f: + image_paths[s] = [l.strip() for l in f.readlines()] +with open(path.join(DATA_DIR, f"seg.txt"), 'r') as f: + seg_paths = [l.strip() for l in f.readlines()] +num_images = len(seg_paths) + +images = [] +images_list = [] +segmentations = [] + +# Read and preprocess each of the paths for each series, and the segmentations. + # print('images number',[TEST_INDEX[img_idx]]) +img_s = {f'{s}': sitk.ReadImage(image_paths[s][img_idx], sitk.sitkFloat32) for s in SERIES} +seg_s = sitk.ReadImage(seg_paths[img_idx], sitk.sitkFloat32) +img_n, seg_n = preprocess(img_s, seg_s, + shape=IMAGE_SHAPE, spacing=TARGET_SPACING) +for seq in img_n: + images.append(img_n[f'{seq}']) +images_list.append(images) +images = [] +segmentations.append(seg_n) + +images_list = np.transpose(images_list, (0, 2, 3, 4, 1)) + +print('>>>>> size image_list nmr 2:', np.shape(images_list), '. equal to: (5, 192, 192, 24, 3)?') + +########### load module ################## +print(' >>>>>>> LOAD MODEL <<<<<<<<<') + +dependencies = { + 'dice_coef': dice_coef, + 'weighted_cross_entropy_fn':weighted_binary_cross_entropy +} +reconstructed_model = load_model(MODEL_PATH, custom_objects=dependencies) +# reconstructed_model.summary(line_length=120) + +# make predictions on all TEST_INDEX +print(' >>>>>>> START prediction <<<<<<<<<') +predictions_blur = reconstructed_model.predict(images_list, batch_size=1) + + +############# preprocess ################# +# preprocess predictions by removing the blur and making individual blobs +print('>>>>>>>> START preprocess') + +def move_dims(arr): + # UMCG numpy dimensions convention: dims = (batch, width, heigth, depth) + # Joeran numpy dimensions convention: dims = (batch, depth, heigth, width) + arr = np.moveaxis(arr, 3, 1) + arr = np.moveaxis(arr, 3, 2) + return arr + +# Joeran has his numpy arrays ordered differently. + +predictions_blur = move_dims(np.squeeze(predictions_blur,axis=4)) +segmentations = move_dims(segmentations) +# predictions = [preprocess_softmax(pred, threshold="dynamic")[0] for pred in predictions_blur] +predictions = predictions_blur +print("the size of predictions is:",np.shape(predictions)) +# Remove outer edges +zeros = np.zeros(np.shape(predictions)) +test = predictions[:,2:-2,2:190,2:190] +zeros[:,2:-2,2:190,2:190] = test +predictions = zeros +print(np.shape(predictions)) +######### Build Saliency heatmap ############## +print(' >>>>>>> Build saliency map <<<<<<<<<') + +ig = IntegratedGradients(reconstructed_model) +saliency_map = [] +for img_idx in range(len(images_list)): + # input_img = np.resize(images_list[img_idx],(1,192,192,24,len(SERIES))) + saliency_map.append(ig.get_mask(images_list).numpy()) + +print("size saliency map",np.shape(saliency_map)) +np.save(f'{YAML_DIR}/saliency_new23',saliency_map) +np.save(f'{YAML_DIR}/images_list_new23',images_list) +np.save(f'{YAML_DIR}/segmentations_new23',segmentations) +np.save(f'{YAML_DIR}/predictions_new23',predictions) + + diff --git a/scripts/15.plot_paper_graphs.py b/scripts/15.plot_paper_graphs.py new file mode 100755 index 0000000..e59a1ef --- /dev/null +++ b/scripts/15.plot_paper_graphs.py @@ -0,0 +1,34 @@ +from umcglib.froc import calculate_froc, plot_froc, plot_multiple_roc, partial_auc, plot_multiple_froc +from sfransen.utils_quintin import * +import numpy as np + +experiment_path1 = './train_output/calc_exp_t2_b1400calc_adccalc_4/umcglib_stats_overlap_0.01.yml' +experiment_path2 = './train_output/calc_exp_t2_b1400calc2_adccalc2_4/umcglib_stats_overlap_0.01.yml' +experiment_path3 = './train_output/calc_exp_t2_b1400calc3_adccalc3_4/umcglib_stats_overlap_0.01.yml' + +## !!!!!!!!!!!!!!!!!! +stats2 = read_yaml_to_dict(experiment_path1) +stats1 = read_yaml_to_dict(experiment_path2) +stats3 = read_yaml_to_dict(experiment_path3) + +plot_multiple_froc( + sensitivities=[np.array(stats1['sensitivity']),np.array(stats2['sensitivity']),np.array(stats3['sensitivity'])], + fp_per_patient=[np.array(stats1["fp_per_patient"]),np.array(stats2["fp_per_patient"]),np.array(stats3["fp_per_patient"])], + ci_low=[np.array(stats1['sens_95_boot_ci_low']),np.array(stats2['sens_95_boot_ci_low']),np.array(stats3['sens_95_boot_ci_low'])], + ci_high=[np.array(stats1["sens_95_boot_ci_high"]),np.array(stats2["sens_95_boot_ci_high"]),np.array(stats3["sens_95_boot_ci_high"])], + model_names=["b50-400","b50-800","b50-400-800"], + title="fROC plot", + height=12, width=15, + xlims=(0.1, 5.0), + save_as="fROC_overlap_0.01.png") + +plot_multiple_roc( + tpr=[np.array(stats1['roc_tpr']),np.array(stats2['roc_tpr']),np.array(stats3['roc_tpr'])], + fpr=[np.array(stats1["roc_fpr"]),np.array(stats2["roc_fpr"]),np.array(stats3["roc_fpr"])], + ci_low=[np.array(stats1['sens_95_boot_ci_low_roc']),np.array(stats2['sens_95_boot_ci_low_roc']),np.array(stats3['sens_95_boot_ci_low_roc'])], + ci_high=[np.array(stats1["sens_95_boot_ci_high_roc"]),np.array(stats2["sens_95_boot_ci_high_roc"]),np.array(stats3["sens_95_boot_ci_high_roc"])], + model_names=["b50_400","b50_800","b50-400-800"], + title="ROC plot", + height=12, width=15, + save_as="ROC_overlap_0.01.png") + diff --git a/scripts/16.plot_paper_saliency.py b/scripts/16.plot_paper_saliency.py new file mode 100755 index 0000000..1fb6648 --- /dev/null +++ b/scripts/16.plot_paper_saliency.py @@ -0,0 +1,89 @@ +import argparse +from ast import Slice +from email.mime import image +import numpy as np +import matplotlib.pyplot as plt +import SimpleITK as sitk + +parser = argparse.ArgumentParser( + description='Calculate the froc metrics and store in froc_metrics.yml') +parser.add_argument('-experiment', + help='Title of experiment') +parser.add_argument('--series', '-s', + metavar='[series_name]', required=True, nargs='+', + help='List of series to include') +args = parser.parse_args() + +########## constants ################# +SERIES = args.series +series_ = '_'.join(args.series) +EXPERIMENT = args.experiment +fold = 0 + +experiments = ['calc_exp_t2_b1400calc3_adccalc3_0','calc_exp_t2_b1400calc2_adccalc2_0','calc_exp_t2_b1400calc_adccalc_0'] +fig, axes = plt.subplots(3,len(SERIES)+1) + +for idx,experiment in enumerate(experiments): + print(idx) + SALIENCY_DIR = f'./../train_output/{experiment}/saliency_new.npy' #_new23 + IMAGES_DIR = f'./../train_output/{experiment}/images_list_new.npy' #_new23 + SEGMENTATION_DIR = f'./../train_output/{experiment}/segmentations_new.npy' #_new23 + predictions_DIR = f'./../train_output/{experiment}/predictions_new.npy' #_new23 + SLIDE = 10 #pat 371 + # SLIDE = 7 #pat 23 + + ########## load saliency map ############ + heatmap = np.load(SALIENCY_DIR) + heatmap = np.squeeze(heatmap) + + ######### load images and segmentations ########### + images_list = np.load(IMAGES_DIR) + images_list = np.squeeze(images_list) + segmentations = np.squeeze(np.load(SEGMENTATION_DIR)) + predictions = np.squeeze(np.load(predictions_DIR)) + + + ######## take average ########## + # len(heatmap) is smaller then maximum number of images + # if len(heatmap) < 100: + # heatmap = np.mean(abs(heatmap),axis=0) + heatmap = abs(heatmap) + + print(np.shape(predictions)) + print(np.shape(segmentations)) + print(np.shape(images_list)) + + max_value = np.amax(heatmap[:,:,SLIDE,:]) + min_value = np.amin(heatmap[:,:,SLIDE,:]) + + TITLES = ['$T2_{tra}$','$DWI_{b1400}$','ADC','Prediction'] + titles = ['All b-values','Omitting b800','Omitting b400'] + for indx in range(len(SERIES)+1): + print(indx) + if indx is len(SERIES): + im = axes[idx,indx].imshow(predictions[SLIDE,:,:],cmap='gray') + print(np.amax(predictions[SLIDE,:,:])) + seg = segmentations[SLIDE,:,:] + axes[idx,indx].imshow(np.ma.masked_where(seg < 0.10, seg),alpha=0.5, vmin=np.amin(seg), vmax=np.amax(seg), cmap='bwr') + if idx is 0: + axes[idx,indx].set_title(TITLES[indx]) + axes[idx,indx].set_axis_off() + axes[idx,indx].set_axis_off() + else: + heatmap_i = np.transpose(np.squeeze(heatmap[:,:,SLIDE,indx])) + im = axes[idx,indx].imshow(np.transpose(images_list[:,:,SLIDE,indx]),cmap='gray') + axes[idx,indx].imshow(np.ma.masked_where(heatmap_i < 0.10, heatmap_i),vmin=min_value, vmax=max_value*0.5, alpha=0.25, cmap='jet') + if idx is 0: + axes[idx,indx].set_title(TITLES[indx]) + # axes[idx,indx].set_axis_off() + axes[idx,indx].set_yticks([]) + axes[idx,indx].set_xticks([]) + if indx is 0: + axes[idx,indx].set_ylabel(titles[idx]) + + + # cbar = fig.colorbar(im, ax=axes.ravel().tolist(), shrink=0.5, orientation='horizontal') + # cbar.set_ticks([min_value,max_value]) +# cbar.set_ticklabels(['less important', 'important']) +# fig.suptitle('Saliency map', fontsize=16) +plt.savefig(f'./../train_output/saliency_map_paper_pat23.png', dpi=300) \ No newline at end of file diff --git a/scripts/17.plot_paper_adc_diff.py b/scripts/17.plot_paper_adc_diff.py new file mode 100755 index 0000000..17624fa --- /dev/null +++ b/scripts/17.plot_paper_adc_diff.py @@ -0,0 +1,92 @@ +import os +from os import path +import SimpleITK as sitk +from sfransen.DWI_exp import preprocess +import numpy as np +import matplotlib.pyplot as plt + +SERIES = ['adccalc2','adccalc','adccalc3'] +TARGET_SPACING = (0.5, 0.5, 3) +INPUT_SHAPE = (192, 192, 24, len(SERIES)) +IMAGE_SHAPE = INPUT_SHAPE[:3] + +DATA_DIR = "./../data/Nijmegen paths/" +########## test with old method ############# +image_paths = {} +for s in SERIES: + with open(path.join(DATA_DIR, f"{s}.txt"), 'r') as f: + image_paths[s] = [l.strip() for l in f.readlines()] +with open(path.join(DATA_DIR, f"seg.txt"), 'r') as f: + seg_paths = [l.strip() for l in f.readlines()] +num_images = len(seg_paths) + +img_idx = 371 + +images = [] +images_list = [] +segmentations = [] + +# Read and preprocess each of the paths for each series, and the segmentations. + # print('images number',[TEST_INDEX[img_idx]]) +img_s = {f'{s}': sitk.ReadImage(image_paths[s][img_idx], sitk.sitkFloat32) for s in SERIES} +seg_s = sitk.ReadImage(seg_paths[img_idx], sitk.sitkFloat32) +img_n, seg_n = preprocess(img_s, seg_s, + shape=IMAGE_SHAPE, spacing=TARGET_SPACING) +for seq in img_n: + images.append(img_n[f'{seq}']) +images_list.append(images) +images = [] +segmentations.append(seg_n) + +images_list = np.squeeze(np.transpose(images_list, (0, 2, 3, 4, 1))) + +print(np.shape(images_list)) +SLIDE = 10 +diff1 = images_list[:,:,SLIDE,0]-images_list[:,:,SLIDE,1] +diff2 = images_list[:,:,SLIDE,0]-images_list[:,:,SLIDE,2] +diff3 = images_list[:,:,SLIDE,1]-images_list[:,:,SLIDE,2] + +fig, axes = plt.subplots(2,len(SERIES)) +fig.suptitle('ADC map differences', fontsize=16) + +maxx_2 = np.amax(images_list[:,:,SLIDE,:]) +minn_2 = np.amin(images_list[:,:,SLIDE,:]) + +TITLES = ['$1) ADC_{b50-b400}$','$2) ADC_{b50-b800}$','$3) ADC_{b50-b400-b800}$'] +for indx in range(len(SERIES)): + print(indx) + im = axes[0,indx].imshow(np.transpose(images_list[:,:,SLIDE,indx]),cmap='gray',vmin=minn_2,vmax=maxx_2) + axes[0,indx].set_title(TITLES[indx]) + axes[0,indx].set_axis_off() + axes[0,indx].set_axis_off() + +maxx_2 = np.amax(images_list[:,:,SLIDE,:]) +minn_2 = np.amin(images_list[:,:,SLIDE,:]) +# print('>>>>>>',minn_2) +cbar_ax = fig.add_axes([0.85, 0.57, 0.02, 0.25]) +cbar2 = fig.colorbar(im, cax=cbar_ax, ticks=[minn_2+0.001, maxx_2-0.001]) +cbar2.ax.set_yticklabels([f'0', f'{1.3}']) + + +maxx = np.amax([np.amax(diff1), np.amax(diff2), np.amax(diff3)]) *0.99 +minn = np.amin([np.amin(diff1), np.amin(diff2), np.amin(diff3)]) + +im = axes[1,0].imshow(np.transpose(diff1),cmap='gray',vmax = maxx,vmin=minn) +axes[1,0].set_axis_off() +axes[1,0].set_axis_off() +axes[1,0].set_title('Protocol 1-2') +im = axes[1,1].imshow(np.transpose(diff2),cmap='gray',vmax = maxx,vmin=minn) +axes[1,1].set_axis_off() +axes[1,1].set_axis_off() +axes[1,1].set_title('Protocol 1-3') + +im = axes[1,2].imshow(np.transpose(diff3),cmap='gray',vmax = maxx,vmin=minn) +axes[1,2].set_axis_off() +axes[1,2].set_axis_off() +axes[1,2].set_title('Protocol 2-3') + +fig.subplots_adjust(right=0.8) +cbar_ax = fig.add_axes([0.85, 0.15, 0.02, 0.25]) +cbar = fig.colorbar(im, cax=cbar_ax, ticks=[minn, 0, maxx]) +cbar.ax.set_yticklabels([f'{round(minn,1)}','0', f'{round(maxx,1)}']) +plt.savefig(f'./../train_output/adc_diff.png', dpi=300) \ No newline at end of file diff --git a/scripts/18.build_db.py b/scripts/18.build_db.py new file mode 100755 index 0000000..4aeb7e3 --- /dev/null +++ b/scripts/18.build_db.py @@ -0,0 +1,254 @@ +import os +from matplotlib.pyplot import table +import glob +import SimpleITK as sitk +import pandas as pd +from sqlite3 import Error +import sqlite3 + +################################ README ###################################### +# TO DO - +# key headers weghalen +# op basis van exclusie +# lokaal +# ssd -> lokaal draaien +# apply parrallel (listen) + +def print_p(text, end="\n"): + """ Print function for on Peregrine. It needs a flush before printing. """ + print(text, flush=True, end=end) + +def create_connection(db_file): + """ create a database connection to the SQLite database + specified by the db_file + :param db_file: database file + :return: Connection object or None + """ + conn = None + try: + conn = sqlite3.connect(db_file) + except Error as e: + print_p(e) + + return conn + +KEY_HEADERS = [ + "0010|0020", + "0018|0089", + "0018|0093", + "0008|103e", + "0028|0010", + "0028|0011", + "0018|9087", + "0018|0024" # Sequence Name + ] + + +INCLUDE_TAGS = [ # Attributes + "0008|0005", # Specific Character Set + "0008|0008", # Image Type + "0008|0012", # Instance Creation Date + "0008|0013", # Instance Creation Time + "0008|0016", # SOP Class UID + "0008|0018", # SOP Instance UID + "0008|0020", # Study Date + "0008|0021", # Series Date + "0008|0022", # Acquisition Date + "0008|0023", # Content Date + "0008|0030", # Study Time + "0008|0031", # Series Time + "0008|0032", # Acquisition Time + "0008|0033", # Content Time + "0008|0050", # Accession Number + "0008|0060", # Modality + "0008|0070", # Manufacturer + "0008|1010", # Station Name + "0008|1030", # Study Description + "0008|103e", # Series Description + "0008|1040", # Institutional Department Name + "0008|1090", # Manufacturer's Model Name + "0010|0020", # Patient ID + "0010|0030", # Patient's Birth Date + "0010|0040", # Patient's Sex + "0010|1010", # Patient's Age + "0010|1020", # Patient's Size + "0010|1030", # Patient's Weight + "0010|21b0", # Additional Patient History + "0012|0062", # Patient Identity Removed + "0012|0063", # De-identification Method + "0018|0015", # Body Part Examined + "0018|0020", # Scanning Sequence + "0018|0021", # Sequence Variant + "0018|0022", # Scan Options + "0018|0023", # MR Acquisition Type + "0018|0050", # Slice Thickness + "0018|0080", # Repetition Time + "0018|0081", # Echo Time + "0018|0083", # Number of Averages + "0018|0084", # Imaging Frequency + "0018|0085", # Imaged Nucleus + "0018|0087", # Magnetic Field Strength + "0018|0088", # Spacing Between Slices + "0018|0089", # Number of Phase Encoding Steps IMPORTANT + "0018|0091", # Echo Train Length + "0018|0093", # Percent Sampling IMPORTANT + "0018|0094", # Percent Phase Field of View + "0018|1000", # Device Serial Number + "0018|1030", # Protocol Name IMPORTANT -> sequence type + "0018|1310", # Acquisition Matrix IMPORTANT + "0018|1312", # In-plane Phase Encoding Direction + "0018|1314", # Flip Angle + "0018|1315", # Variable Flip Angle Flag + "0018|5100", # Patient Position + "0018|9087", # Diffusion b-value IMPORTANT + "0020|000d", # Study Instance UID + "0020|000e", # Series Instance UID + "0020|0010", # Study ID + "0020|0032", # Image Position (Patient) + "0020|0037", # Image Orientation (Patient) + "0020|0052", # Frame of Reference UID + "0020|1041", # Slice Location + "0028|0002", # Samples per Pixel + "0028|0010", # Rows IMPORTANT + "0028|0011", # Columns IMPORTANT + "0028|0030", # Pixel Spacing + "0028|0100", # Bits Allocated + "0028|0101", # Bits Stored + "0028|0106", # Smallest Image Pixel Value + "0028|0107", # Largest Image Pixel Value + "0028|1050", # Window Center + "0028|1051", # Window Width + "0040|0244", # Performed Procedure Step Start Date + "0040|0254" # Performed Procedure Step Description + ] + + +################################################################################ + + +def get_dict_from_dicom(reader, verbose=False): + headers = {} + for header_name in INCLUDE_TAGS: + headers[header_name] = None + + for k in reader.GetMetaDataKeys(): + if k in INCLUDE_TAGS: + v = reader.GetMetaData(k) + headers[k] = f"{v}" + if verbose: + print_p(f"({k}) = \"{v}\"") + headers["path"] = "" + return headers + + +def has_different_key_headers(current_header_dict: dict, prev_header_dict): + """ This function returns False if one of the key headers is different in + both dictionaries supplied as arguments. + + Parameters: + `current_header_dict (dict)`: dict from dicom (Headers from DICOM) + `prev_header_dict (dict)`: dict from dicom (Headers from DICOM) + returns (bool): True if important headers are different, else False + """ + for header in KEY_HEADERS: + try: + if current_header_dict[header] != prev_header_dict.get(header, None): + return True + except: + continue + return False + + +def is_patient_in_database(conn, tablename, patient): + # Get all results from patient from database + cur = conn.cursor() + query = f"SELECT [0010|0020] FROM {tablename} WHERE [0010|0020] like '%{patient}%';" + result = cur.execute(query).fetchall() #list of tuples + if len(result) == 0: + return False + return True + + +def fill_dicom_table_RUMC_UMCG( + tablename: str, + database: str, + patients_dir_RUMC: str, + devmode = False): + """ Fills the given table with headers/tags from DICOM files from UMCG and + RUMC. The tags are cross referenced with an include list of tags. + + Parameters: + `tablename (string)`: table in sqlite that will be inserted into + `database (string)`: relative project path to .db (database) file for sqlite. + `patients_dir_RUMC (string)`: path where patient directories are stored (RUMC) + `patients_dir_UMCG (string)`: path where patient directories are stored (UMCG) + """ + + # Connect with database + db_path = f"{os.getcwd()}{database}" + conn = create_connection(db_path) + print_p(f"connection made: {db_path}") + + # patients = os.listdir(patients_dir_UMCG) + os.listdir(patients_dir_RUMC) + patients = os.listdir(patients_dir_RUMC) + prev_headers = {} + + with conn: + # Drop all rows from table if it exists. + if False: + conn.execute(f"DELETE FROM {tablename};") + print_p("done deleting all records from database") + + # loop over all patients. (RUMC and UMCG) + for p_idx, patient in enumerate(patients): + + print_p(f"\nPatient {p_idx}: {patient}") + + if is_patient_in_database(conn, tablename, patient): + print_p(f"PATIENT IS ALREADY IN DATABASE {tablename}") + continue + + print_p(f"patient: {patient} is not in database") + # Find all DICOM files + glob_pattern = f"data/raw/*/{patient}/**/*.dcm" + dicoms_paths = glob.glob(glob_pattern, recursive=True) + rows = [] + + # Loop over DICOM files + for f_idx, dcm_path in enumerate(dicoms_paths): + if f_idx > 10 and devmode: + continue + print_p(f"f{f_idx}", end=' ') + + try: + reader = sitk.ImageFileReader() + reader.SetFileName(dcm_path) + reader.LoadPrivateTagsOn() + reader.ReadImageInformation() + + except: + print_p(f"Read Image Information EXCEPTION... Skipping: {dcm_path}") + continue + + curr_headers = get_dict_from_dicom(reader, verbose=False) + curr_headers['path'] = dcm_path + if not has_different_key_headers(curr_headers, prev_headers): + continue + prev_headers = curr_headers + rows.append(curr_headers) + + df = pd.DataFrame.from_dict(rows, orient='columns') + print_p(f"\nwriting headers to sqlite database. {tablename} - num rows: {len(rows)}") + df.to_sql(name=tablename, con=conn, if_exists='append') + + print_p(f"\n--- DONE writing data to {tablename}---") + + +################################################################################ +print_p("start script") +fill_dicom_table_RUMC_UMCG( + tablename = "dicom_headers_v2", + database = r"dicoms_rumc.db", + patients_dir_RUMC = r"data/raw/RUMC", + patients_dir_UMCG = r"data/raw/UMCG", + devmode=False) \ No newline at end of file diff --git a/scripts/19.clinical_variables.py b/scripts/19.clinical_variables.py new file mode 100755 index 0000000..0850b02 --- /dev/null +++ b/scripts/19.clinical_variables.py @@ -0,0 +1,134 @@ +from multiprocessing.sharedctypes import Value +import xml.etree.ElementTree as ET +import os +import pathlib +from umcglib.utils import apply_parallel +import numpy as np +from sfransen.utils_quintin import * + + +def parse_marklist(marklistpath): + tree = ET.parse(marklistpath) + root = tree.getroot() + lesions = {} + patient_element = (list(root.iter("markpatient")) + [None])[0] + lesions['PSA'] = patient_element.find("PSA").text if (patient_element is not None and patient_element.find("PSA") is not None) else 0 + number_of_lesions = [] + current_max_PIRADS = 0 + for mark in root.iter("mark"): + PIRADS = mark.find("PIRADS").text if mark.find("PIRADS") is not None else 0 + if int(PIRADS) > 0: + number_of_lesions.append(PIRADS) + if int(PIRADS) > int(current_max_PIRADS): + current_max_PIRADS = PIRADS + + # lesions_ = 1 if mark.find("PIRADS") is not None else 0 + # number_of_lesions += number_of_lesions + lesions_ + # if current_max_PIRADS == 0: + # if len(number_of_lesions) > 0: + # print(f'no PIRADS, wel lesie {number_of_lesions}') + + lesions['PIRADS'] = current_max_PIRADS + lesions['number_of_lesions'] = len(number_of_lesions) + return lesions + +def parse_age(path): + tree = ET.parse(path) + root = tree.getroot() + age = root[6].text + return age[1:-1] + +def mean_above_zero(df): + df = df[df != 0] + print(df) + return np.mean(df) + +def std_above_zero(df): + df = df[df != 0] + return np.std(df) + +def median_above_zero(df): + df = df[df != 0] + return np.median(df) + +def interq(df): + df = df[df != 0] + q3, q1 = np.percentile(df, [75 ,25]) + iqr = q3 - q1 + return iqr + +# Get pat from X:/sfransen/data/Nijmegen paths/seg +# /data/pca-rad/datasets/radboud_lesions_2022/pat0617-2016.nii.gz +with open("./../data/Nijmegen paths/b50.txt", 'r') as f: + b50_paths = [l.strip() for l in f.readlines()] + +marklistpaths = [] +info_ages = [] +pat_ids = [] +for b50_path in b50_paths: + path_part = pathlib.Path(b50_path).parts + pat_id = path_part[5] + # print(pat_id) + marklistpath = os.path.join(path_part[0],path_part[1],path_part[2],path_part[3],path_part[4],path_part[5],path_part[6],'markdatasetlist.xml') + info_age = os.path.join(path_part[0],path_part[1],path_part[2],path_part[3],path_part[4],path_part[5],path_part[6],'t2_tse_sag','info.xml') + marklistpaths.append(marklistpath) + info_ages.append(info_age) + pat_ids.append(pat_id) + +PSA_PIRADS = apply_parallel( + list(marklistpaths), + function = parse_marklist) + +AGE = apply_parallel( + list(info_ages), + function = parse_age, +) +PSA_PIRADS = np.stack(PSA_PIRADS) + +PSA = [(int(x['PSA']) if x['PSA'] is not None else 0) for x in PSA_PIRADS] +PIRADS = np.array([int(x['PIRADS']) for x in PSA_PIRADS]) +# number_of_lesions = [x['number_of_lesions'] for x in PSA_PIRADS] +# number_of_lesions = np.array([int(item) for sublist in number_of_lesions for item in sublist] ) +number_of_lesions = np.array([int(x['number_of_lesions']) for x in PSA_PIRADS]) + +AGE = np.array([(int(x) if x is not None else 0) for x in AGE]) +patients = len(pat_ids) +patients_age_median = median_above_zero(AGE) +patients_age_iqr = interq(AGE) +patients_psa_median = median_above_zero(np.array(PSA)) +patients_psa_iqr = interq(np.array(PSA)) + +csPCA_patients = np.sum(PIRADS>3) +PSA_csPCA_patients_median = median_above_zero(np.multiply(PIRADS>3,PSA)) +PSA_csPCA_patients_iqr = interq(np.multiply(PIRADS>3,PSA)) +AGE_csPCA_patients_median = median_above_zero(np.multiply(PIRADS>3,AGE)) +AGE_csPCA_patients_iqr = interq(np.multiply(PIRADS>3,AGE)) + +healthy_patients = patients - csPCA_patients +AGE_healthy_patients_median = median_above_zero(np.multiply(PIRADS<4,AGE)) +AGE_healthy_patients_iqr = interq(np.multiply(PIRADS<4,AGE)) +PSA_healthy_patients_median = median_above_zero(np.multiply(PIRADS<4,PSA)) +PSA_healthy_patients_iqr = interq(np.multiply(PIRADS<4,PSA)) + +PIRADS_0 = np.sum(PIRADS==0) +PIRADS_1 = np.sum(PIRADS==1) +PIRADS_2 = np.sum(PIRADS==2) +PIRADS_3 = np.sum(PIRADS==3) +PIRADS_4 = np.sum(PIRADS==4) +PIRADS_5 = np.sum(PIRADS==5) + +LESIONS_0 = np.sum(number_of_lesions==0) +LESIONS_1 = np.sum(number_of_lesions==1) +LESIONS_2 = np.sum(number_of_lesions==2) +LESIONS_3 = np.sum(number_of_lesions==3) +LESIONS_4 = np.sum(number_of_lesions==4) +LESIONS_5 = np.sum(number_of_lesions==5) +LESIONS_6 = np.sum(number_of_lesions>5) + + +print(f"patients, total:{patients}, median AGE:{patients_age_median} iqr:{patients_age_iqr}, median PSA:{patients_psa_median} iqr:{patients_psa_iqr}") +print(f"healthy patients: total:{healthy_patients}, median AGE:{AGE_healthy_patients_median} iqr {AGE_healthy_patients_iqr}, median PSA:{PSA_healthy_patients_median} , iqr PSA:{PSA_healthy_patients_iqr}") +print(f"csPCA patients: total:{csPCA_patients}, median AGE:{AGE_csPCA_patients_median} iqr {AGE_csPCA_patients_iqr} , median PSA:{PSA_csPCA_patients_median} , iqr PSA:{PSA_csPCA_patients_iqr}") +print(f"Patient PIRADS count: Patients 0: {PIRADS_0}, Patients 1:{PIRADS_1}, Patient 2: {PIRADS_2}, Patients 3:{PIRADS_3} , Patients 4:{PIRADS_4} , Patients 5:{PIRADS_5} ") +print(f"Lesion count: Lesions 0: {LESIONS_0}, Lesions 1:{LESIONS_1}, Lesions 2: {LESIONS_2}, Lesions 3:{LESIONS_3} , Lesions 4:{LESIONS_4} , Lesions 5:{LESIONS_5}, Lesions >5:{LESIONS_6} ") + diff --git a/scripts/4.frocs.py b/scripts/4.frocs.py index ab31a37..15a0360 100755 --- a/scripts/4.frocs.py +++ b/scripts/4.frocs.py @@ -18,7 +18,10 @@ from sfransen.DWI_exp.callbacks import dice_coef from sfransen.FROC.cal_froc_from_np import * from sfransen.load_images import load_images_parrallel from sfransen.DWI_exp.losses import weighted_binary_cross_entropy - +from umcglib.froc import calculate_froc, plot_froc, plot_multiple_froc, partial_auc +from umcglib.binarize import dynamic_threshold +from umcglib.utils import set_gpu +set_gpu(gpu_idx=1) parser = argparse.ArgumentParser( description='Calculate the froc metrics and store in froc_metrics.yml') @@ -119,7 +122,7 @@ images_list = [] segmentations = [] # Read and preprocess each of the paths for each series, and the segmentations. -for img_idx in tqdm(range(len(TEST_INDEX))): #[:40]): #for less images +for img_idx in tqdm(range(len(TEST_INDEX))): #for less images # print('images number',[TEST_INDEX[img_idx]]) img_s = {f'{s}': sitk.ReadImage(image_paths[s][TEST_INDEX[img_idx]], sitk.sitkFloat32) for s in SERIES} seg_s = sitk.ReadImage(seg_paths[TEST_INDEX[img_idx]], sitk.sitkFloat32) @@ -133,7 +136,7 @@ for img_idx in tqdm(range(len(TEST_INDEX))): #[:40]): #for less images images_list = np.transpose(images_list, (0, 2, 3, 4, 1)) -print('>>>>> size image_list nmr 2:', np.shape(images_list), '. equal to: (5, 192, 192, 24, 3)?') +# print('>>>>>DEBUG size image_list nmr 2:', np.shape(images_list), '. equal to: (5, 192, 192, 24, 3)?') ########### load module ################## print(' >>>>>>> LOAD MODEL <<<<<<<<<') @@ -171,11 +174,10 @@ test = np.squeeze(predictions)[:,2:-2,2:190,2:190] zeros[:,2:-2,2:190,2:190] = test predictions = zeros -# perform Froc +# perform Froc method joeran metrics = evaluate(y_true=segmentations, y_pred=predictions) dump_dict_to_yaml(metrics, YAML_DIR, "froc_metrics_focal_10_test", verbose=True) - ############## save image as example ################# # save image nmr 2 img_s = sitk.GetImageFromArray(predictions_blur[2].squeeze()) @@ -190,34 +192,6 @@ sitk.WriteImage(img_s, f"{IMAGE_DIR}/segmentations_002_old.nii.gz") img_s = sitk.GetImageFromArray(np.transpose(images_list[2,:,:,:,0].squeeze())) sitk.WriteImage(img_s, f"{IMAGE_DIR}/t2_002_old.nii.gz") -# save image nmr 3 -img_s = sitk.GetImageFromArray(predictions_blur[3].squeeze()) -sitk.WriteImage(img_s, f"{IMAGE_DIR}/predictions_blur_003_old.nii.gz") -img_s = sitk.GetImageFromArray(predictions[3].squeeze()) -sitk.WriteImage(img_s, f"{IMAGE_DIR}/predictions_003_old.nii.gz") -img_s = sitk.GetImageFromArray(segmentations[3].squeeze()) -sitk.WriteImage(img_s, f"{IMAGE_DIR}/segmentations_003_old.nii.gz") -img_s = sitk.GetImageFromArray(np.transpose(images_list[3,:,:,:,0].squeeze())) -sitk.WriteImage(img_s, f"{IMAGE_DIR}/t2_003_old.nii.gz") - -img_s = sitk.GetImageFromArray(np.transpose(images_list[3,:,:,:,1].squeeze())) -sitk.WriteImage(img_s, f"{IMAGE_DIR}/highb_003_old.nii.gz") - -# save image nmr 3 -img_s = sitk.GetImageFromArray(predictions_blur[4].squeeze()) -sitk.WriteImage(img_s, f"{IMAGE_DIR}/predictions_blur_004_old.nii.gz") - -img_s = sitk.GetImageFromArray(predictions[4].squeeze()) -sitk.WriteImage(img_s, f"{IMAGE_DIR}/predictions_004_old.nii.gz") - -img_s = sitk.GetImageFromArray(segmentations[4].squeeze()) -sitk.WriteImage(img_s, f"{IMAGE_DIR}/segmentations_004_old.nii.gz") - -img_s = sitk.GetImageFromArray(np.transpose(images_list[4,:,:,:,0].squeeze())) -sitk.WriteImage(img_s, f"{IMAGE_DIR}/t2_004_old.nii.gz") - -img_s = sitk.GetImageFromArray(np.transpose(images_list[4,:,:,:,1].squeeze())) -sitk.WriteImage(img_s, f"{IMAGE_DIR}/highb_004_old.nii.gz") \ No newline at end of file diff --git a/scripts/7.Visualize_saliency.py b/scripts/7.Visualize_saliency.py index d68214c..ba37d6c 100755 --- a/scripts/7.Visualize_saliency.py +++ b/scripts/7.Visualize_saliency.py @@ -1,4 +1,5 @@ import argparse +from email.mime import image import numpy as np import matplotlib.pyplot as plt import SimpleITK as sitk @@ -16,9 +17,10 @@ args = parser.parse_args() SERIES = args.series series_ = '_'.join(args.series) EXPERIMENT = args.experiment -SALIENCY_DIR = f'./../train_output/{EXPERIMENT}_{series_}/saliency.npy' -IMAGES_DIR = f'./../train_output/{EXPERIMENT}_{series_}/images_list.npy' -SEGMENTATION_DIR = f'./../train_output/{EXPERIMENT}_{series_}/segmentations.npy' +fold = 0 +SALIENCY_DIR = f'./../train_output/{EXPERIMENT}_{series_}_{fold}/saliency.npy' +IMAGES_DIR = f'./../train_output/{EXPERIMENT}_{series_}_{fold}/images_list.npy' +SEGMENTATION_DIR = f'./../train_output/{EXPERIMENT}_{series_}_{fold}/segmentations.npy' SLIDE = 10 ########## load saliency map ############ @@ -44,8 +46,9 @@ min_value = np.amin(heatmap[:,:,SLIDE,:]) for indx in range(len(SERIES)): print(indx) - axes[0,indx].imshow(np.transpose(images_list[:,:,SLIDE,indx]),cmap='gray') - im = axes[1,indx].imshow(np.transpose(np.squeeze(heatmap[:,:,SLIDE,indx])),vmin=min_value, vmax=max_value) + heatmap_i = np.transpose(np.squeeze(heatmap[:,:,SLIDE,indx])) + im = axes[0,indx].imshow(np.transpose(images_list[:,:,SLIDE,indx]),cmap='gray') + axes[0,indx].imshow(np.ma.masked_where(heatmap_i < 0.10, heatmap_i),vmin=min_value, vmax=max_value*0.5, alpha=0.25, cmap='jet') axes[0,indx].set_title(SERIES[indx]) axes[0,indx].set_axis_off() axes[1,indx].set_axis_off() @@ -54,4 +57,4 @@ cbar = fig.colorbar(im, ax=axes.ravel().tolist(), shrink=0.5, orientation='horiz cbar.set_ticks([min_value,max_value]) cbar.set_ticklabels(['less important', 'important']) fig.suptitle('Saliency map', fontsize=16) -plt.savefig(f'./../train_output/{EXPERIMENT}_{series_}/saliency_map.png', dpi=300) \ No newline at end of file +plt.savefig(f'./../train_output/{EXPERIMENT}_{series_}_{fold}/saliency_map.png', dpi=300) \ No newline at end of file diff --git a/scripts/calc_adc_b1400.py b/scripts/calc_adc_b1400.py index c7edc63..05d79a1 100755 --- a/scripts/calc_adc_b1400.py +++ b/scripts/calc_adc_b1400.py @@ -4,15 +4,25 @@ from tqdm import tqdm import numpy as np import SimpleITK as sitk -def calc_adc(b50,b400): - mean_dwi = (50 + 400) / 2 - mean_si = np.divide(np.add(np.log(b50), np.log(b400)), 2) +# def calc_adc(b50,b400): +# mean_dwi = (50 + 400) / 2 +# mean_si = np.divide(np.add(np.log(b50), np.log(b400)), 2) - denominator = np.multiply((50 - mean_dwi), np.subtract(np.log(b50), mean_si)) + np.multiply((400 - mean_dwi), np.subtract(np.log(b400), mean_si)) - numerator = np.power((50 - mean_dwi), 2) + np.power((400 - mean_dwi), 2) +# denominator = np.multiply((50 - mean_dwi), np.subtract(np.log(b50), mean_si)) + np.multiply((400 - mean_dwi), np.subtract(np.log(b400), mean_si)) +# numerator = np.power((50 - mean_dwi), 2) + np.power((400 - mean_dwi), 2) +# adc_with_zeros = np.divide(denominator, numerator) * -1000000 +# adc = np.clip(adc_with_zeros,0,np.amax(adc_with_zeros)) +# return adc + +def calc_adc(b50, b400, b800): + "Calculates the adc based on b50, b400 and b800 DWI images/arrays." + mean_dwi = (50 + 400 + 800) / 3 + mean_si = np.divide(np.add(np.add(np.log(b50), np.log(b400)), np.log(b800)), 3) + denominator = np.multiply((50 - mean_dwi), np.subtract(np.log(b50), mean_si)) + np.multiply((400 - mean_dwi), np.subtract(np.log(b400), mean_si)) + np.multiply((800 - mean_dwi), np.subtract(np.log(b800), mean_si)) + numerator = np.power((50 - mean_dwi), 2) + np.power((400 - mean_dwi), 2) + np.power((800 - mean_dwi), 2) adc_with_zeros = np.divide(denominator, numerator) * -1000000 adc = np.clip(adc_with_zeros,0,np.amax(adc_with_zeros)) - return adc + return adc def calc_high_b(b_value_high,b_value,b_image,ADC_map): high_b = np.multiply(b_image, np.exp(np.multiply(np.subtract(b_value,b_value_high), (np.divide(ADC_map,1000000))))) @@ -33,7 +43,7 @@ def append_new_line(file_name, text_to_append): -series = ['b50','b400'] +series = ['b50','b400','b800'] # series = ['t2'] DATA_DIR = "./../data/Nijmegen paths/" @@ -55,14 +65,14 @@ for img_idx in tqdm(range(num_images)): arr_b50 = sitk.GetArrayFromImage(img_b50) img_b400 = sitk.ReadImage(image_paths['b400'][img_idx], sitk.sitkFloat32) arr_b400 = sitk.GetArrayFromImage(img_b400) - # img_b800 = sitk.ReadImage(image_paths['b800'][img_idx], sitk.sitkFloat32) - # arr_b800 = sitk.GetArrayFromImage(img_b800) + img_b800 = sitk.ReadImage(image_paths['b800'][img_idx], sitk.sitkFloat32) + arr_b800 = sitk.GetArrayFromImage(img_b800) # img_t2 = sitk.ReadImage(image_paths['t2'][img_idx], sitk.sitkFloat32) # img_t2 = sitk.GetArrayFromImage(img_t2) # img_seg = sitk.ReadImage(seg_paths[img_idx], sitk.sitkFloat32) # img_seg = sitk.GetArrayFromImage(img_seg) - adc = calc_adc(arr_b50,arr_b400) + adc = calc_adc(arr_b50,arr_b400,arr_b800) high_b = calc_high_b(1400,50,arr_b50,adc) adc = sitk.GetImageFromArray(adc) @@ -71,8 +81,8 @@ for img_idx in tqdm(range(num_images)): # seg = sitk.GetImageFromArray(img_seg) patient_ID = os.path.split(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(image_paths['b50'][img_idx])))))[1] - path_adc = f'./../data/adc_calc_2/{patient_ID}.nii.gz' - path_high_b = f'./../data/b1400_calc_2/{patient_ID}.nii.gz' + path_adc = f'./../data/adc_calc_3/{patient_ID}.nii.gz' + path_high_b = f'./../data/b1400_calc_3/{patient_ID}.nii.gz' # patient_ID = os.path.split(os.path.dirname(os.path.dirname(os.path.dirname(image_paths['t2'][img_idx]))))[1] # path_t2 = f'./../data/t2_calc/{patient_ID}.nii.gz' # path_seg = f'./../data/seg_calc/{patient_ID}.nii.gz' @@ -84,8 +94,8 @@ for img_idx in tqdm(range(num_images)): # sitk.WriteImage(t2, path_t2) # sitk.WriteImage(seg, path_seg) - append_new_line('adccalc2.txt',path_adc) - append_new_line('b1400calc2.txt',path_high_b) + append_new_line('adccalc3.txt',path_adc) + append_new_line('b1400calc3.txt',path_high_b) # append_new_line('t2calc.txt',path_t2) # append_new_line('segcalc.txt',path_seg) diff --git a/scripts/heatmap_result_1.png b/scripts/heatmap_result_1.png new file mode 100644 index 0000000000000000000000000000000000000000..098ca10b1bb30299019847dfda4c610eb65ac64c GIT binary patch literal 94142 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