[637b40]: / adpkd_segmentation / evaluation / eval_model_assisted.py

Download this file

138 lines (105 with data), 3.9 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
from pathlib import Path
import numpy as np
import pandas as pd
from collections import defaultdict
from argparse import ArgumentParser
import pprint
from pydicom import dcmread
import nibabel as nib
from adpkd_segmentation.evaluation.evaluation_utils import exam_preds_to_stat
MODEL = "model"
MODEL_ASSISTED = "model_assisted"
VOX_VOL = "vox_vol"
STUDY = "study"
parser = ArgumentParser()
pp = pprint.PrettyPrinter(indent=4)
parser.add_argument(
"-i",
"--input_path",
type=str,
help="path to model predictions and model_assisted_annotation",
default="/big_data2/apkd_segmentation/storage/output/saved_inference/adpkd-segmentation-pytorch",
)
parser.add_argument(
"-o",
"--output_path",
type=str,
help="path to output dictory",
default="/home/akg9006/test_model_assisted",
)
def pred_ground_paths_dict(input_path, ground_keys=["a_vol.nii", "a.nii"]):
"""Returns a dictionary with prediction, ground, and voxel volume."""
folder_to_data = defaultdict(dict)
model_pred = list(input_path.glob("**/pred_vol.nii"))
model_assisted = []
for gk in ground_keys:
model_assisted.extend(list(input_path.glob(f"**/{gk}")))
for mp in model_pred:
folder_to_data[mp.parent][MODEL] = mp
for ma in model_assisted:
assert (
MODEL_ASSISTED not in folder_to_data[ma.parent]
), f"Only one ground_truth volume per folder. Check {ma.parent}"
folder_to_data[ma.parent][MODEL_ASSISTED] = ma
folder_to_data = {
k: v
for k, v in folder_to_data.items()
if MODEL in v and MODEL_ASSISTED in v
}
for k, v in folder_to_data.items():
# extract voxel_volume from some dicom in parent folder
dcms = list(k.parent.glob("*.dcm"))
assert (
len(dcms) > 0
), f"Dicom files required in {k.parent} for volume calculations"
if len(dcms) > 0:
pdcm = dcmread(dcms[0])
dX_Y = float(pdcm.PixelSpacing[0])
dZ = float(pdcm.SpacingBetweenSlices)
vox_vol = dZ * (dX_Y ** 2)
# print(f"DCM: {dcms[0].name} vox_vol: {vox_vol}")
v[VOX_VOL] = vox_vol
for k, v in folder_to_data.items():
v[STUDY] = str(v[MODEL].parent.relative_to(input_path))
return folder_to_data
def compute_pred_vs_ground(
folder_to_date, output=None, exclude_keys=["scale_factor", "Pred_stdev"]
):
"""Consumes dictionary with paths to model, model_assisted and
data for voxel_volume. Computes dice and TKV calculations.
Args:
folder_to_date (dict): Contains keys MODEL, MODEL_ASSITED, VOX_VOLUME
Returns:
pd.DataFrame: Contains results for each study
"""
all_stats = defaultdict(list)
for k, v in folder_to_data.items():
pred_vol = nib.load(v[MODEL]).get_fdata()
pred_vol = np.expand_dims(pred_vol, axis=0)
ground_vol = nib.load(v[MODEL_ASSISTED]).get_fdata()
ground_vol = np.expand_dims(ground_vol, axis=0)
vox_vol = v[VOX_VOL]
study = v[STUDY]
stat = exam_preds_to_stat(
pred_vol=pred_vol,
ground_vol=ground_vol,
vox_vol=vox_vol,
study=study,
)
for k, v in stat.items():
if k not in exclude_keys:
all_stats[k].append(v)
df = pd.DataFrame.from_dict(all_stats)
if output is not None:
if output.is_dir():
output = output / "model_assisted_vs_model.csv"
df.to_csv(output)
return df
if __name__ == "__main__":
args = parser.parse_args()
input_path = Path(args.input_path)
output_path = Path(args.output_path)
folder_to_data = pred_ground_paths_dict(input_path)
print(f"Generating stats. Input: {input_path} Output: {output_path}")
all_stats = compute_pred_vs_ground(folder_to_data, output_path)
print(all_stats)