Added support for all preop brain tumor types
Browse files- neukit/gui.py +46 -9
- neukit/inference.py +43 -36
neukit/gui.py
CHANGED
@@ -4,7 +4,7 @@ from .inference import run_model
|
|
4 |
|
5 |
|
6 |
class WebUI:
|
7 |
-
def __init__(self, model_name:str = None,
|
8 |
# global states
|
9 |
self.images = []
|
10 |
self.pred_images = []
|
@@ -13,9 +13,25 @@ class WebUI:
|
|
13 |
self.nb_slider_items = 150
|
14 |
|
15 |
self.model_name = model_name
|
16 |
-
self.class_name = class_name
|
17 |
self.cwd = cwd
|
18 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
# define widgets not to be rendered immediantly, but later on
|
20 |
self.slider = gr.Slider(1, self.nb_slider_items, value=1, step=1, label="Which 2D slice to show")
|
21 |
self.volume_renderer = gr.Model3D(
|
@@ -24,6 +40,10 @@ class WebUI:
|
|
24 |
visible=True,
|
25 |
elem_id="model-3d",
|
26 |
).style(height=512)
|
|
|
|
|
|
|
|
|
27 |
|
28 |
def combine_ct_and_seg(self, img, pred):
|
29 |
return (img, [(pred, self.class_name)])
|
@@ -33,7 +53,7 @@ class WebUI:
|
|
33 |
|
34 |
def load_mesh(self, mesh_file_name):
|
35 |
path = mesh_file_name.name
|
36 |
-
run_model(path, model_path=self.cwd + "resources/models/")
|
37 |
nifti_to_glb("prediction.nii.gz")
|
38 |
|
39 |
self.images = load_ct_to_numpy(path)
|
@@ -56,25 +76,42 @@ class WebUI:
|
|
56 |
height: 512px;
|
57 |
margin: auto;
|
58 |
}
|
|
|
|
|
|
|
59 |
"""
|
60 |
with gr.Blocks(css=css) as demo:
|
61 |
|
62 |
with gr.Row():
|
63 |
-
|
64 |
-
|
65 |
-
).style(full_width=False, size="sm")
|
66 |
file_output.upload(self.upload_file, file_output, file_output)
|
67 |
|
68 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
69 |
run_btn.click(
|
70 |
fn=lambda x: self.load_mesh(x),
|
71 |
inputs=file_output,
|
72 |
-
outputs=self.volume_renderer
|
73 |
)
|
74 |
|
75 |
with gr.Row():
|
76 |
gr.Examples(
|
77 |
-
examples=[self.cwd + "RegLib_C01_2.nii"],
|
78 |
inputs=file_output,
|
79 |
outputs=file_output,
|
80 |
fn=self.upload_file,
|
|
|
4 |
|
5 |
|
6 |
class WebUI:
|
7 |
+
def __init__(self, model_name:str = None, cwd:str = "/home/user/app/"):
|
8 |
# global states
|
9 |
self.images = []
|
10 |
self.pred_images = []
|
|
|
13 |
self.nb_slider_items = 150
|
14 |
|
15 |
self.model_name = model_name
|
|
|
16 |
self.cwd = cwd
|
17 |
|
18 |
+
self.class_name = "meningioma" # default - but can be updated based on which task is chosen from dropdown
|
19 |
+
self.class_names = {
|
20 |
+
"meningioma": "MRI_Meningioma",
|
21 |
+
"low-grade": "MRI_LGGlioma",
|
22 |
+
"metastasis": "MRI_Metastasis",
|
23 |
+
"high-grade": "MRI_GBM",
|
24 |
+
"brain": "MRI_Brain",
|
25 |
+
}
|
26 |
+
|
27 |
+
self.result_names = {
|
28 |
+
"meningioma": "Tumor",
|
29 |
+
"low-grade": "Tumor",
|
30 |
+
"metastasis": "Tumor",
|
31 |
+
"high-grade": "Tumor",
|
32 |
+
"brain": "Brain",
|
33 |
+
}
|
34 |
+
|
35 |
# define widgets not to be rendered immediantly, but later on
|
36 |
self.slider = gr.Slider(1, self.nb_slider_items, value=1, step=1, label="Which 2D slice to show")
|
37 |
self.volume_renderer = gr.Model3D(
|
|
|
40 |
visible=True,
|
41 |
elem_id="model-3d",
|
42 |
).style(height=512)
|
43 |
+
|
44 |
+
def set_class_name(self, value):
|
45 |
+
print("Changed task to:", value)
|
46 |
+
self.class_name = value
|
47 |
|
48 |
def combine_ct_and_seg(self, img, pred):
|
49 |
return (img, [(pred, self.class_name)])
|
|
|
53 |
|
54 |
def load_mesh(self, mesh_file_name):
|
55 |
path = mesh_file_name.name
|
56 |
+
run_model(path, model_path=self.cwd + "resources/models/", task=self.class_names[self.class_name], name=self.result_names[self.class_name])
|
57 |
nifti_to_glb("prediction.nii.gz")
|
58 |
|
59 |
self.images = load_ct_to_numpy(path)
|
|
|
76 |
height: 512px;
|
77 |
margin: auto;
|
78 |
}
|
79 |
+
#upload {
|
80 |
+
height: 120px;
|
81 |
+
}
|
82 |
"""
|
83 |
with gr.Blocks(css=css) as demo:
|
84 |
|
85 |
with gr.Row():
|
86 |
+
|
87 |
+
file_output = gr.File(file_count="single", elem_id="upload") # elem_id="upload"
|
|
|
88 |
file_output.upload(self.upload_file, file_output, file_output)
|
89 |
|
90 |
+
# with gr.Column():
|
91 |
+
|
92 |
+
model_selector = gr.Dropdown(
|
93 |
+
list(self.class_names.keys()),
|
94 |
+
label="Task",
|
95 |
+
info="Which task to perform - one model for each brain tumor type and brain extraction",
|
96 |
+
multiselect=False,
|
97 |
+
size="sm",
|
98 |
+
)
|
99 |
+
model_selector.input(
|
100 |
+
fn=lambda x: self.set_class_name(x),
|
101 |
+
inputs=model_selector,
|
102 |
+
outputs=None,
|
103 |
+
)
|
104 |
+
|
105 |
+
run_btn = gr.Button("Run analysis").style(full_width=False, size="lg")
|
106 |
run_btn.click(
|
107 |
fn=lambda x: self.load_mesh(x),
|
108 |
inputs=file_output,
|
109 |
+
outputs=self.volume_renderer,
|
110 |
)
|
111 |
|
112 |
with gr.Row():
|
113 |
gr.Examples(
|
114 |
+
examples=[self.cwd + "RegLib_C01_1.nii", self.cwd + "RegLib_C01_2.nii"],
|
115 |
inputs=file_output,
|
116 |
outputs=file_output,
|
117 |
fn=self.upload_file,
|
neukit/inference.py
CHANGED
@@ -5,7 +5,7 @@ import logging
|
|
5 |
import traceback
|
6 |
|
7 |
|
8 |
-
def run_model(input_path: str, model_path: str, verbose: str = "info", task: str = "MRI_Meningioma"):
|
9 |
logging.basicConfig()
|
10 |
logging.getLogger().setLevel(logging.WARNING)
|
11 |
|
@@ -17,49 +17,56 @@ def run_model(input_path: str, model_path: str, verbose: str = "info", task: str
|
|
17 |
logging.getLogger().setLevel(logging.ERROR)
|
18 |
else:
|
19 |
raise ValueError("Unsupported verbose value provided:", verbose)
|
20 |
-
|
21 |
-
# create sequence folder, rename patient, and add to temporary patient directory
|
22 |
-
filename = input_path.split("/")[-1]
|
23 |
-
splits = filename.split(".")
|
24 |
-
extension = ".".join(splits[1:])
|
25 |
-
patient_directory = "./patient/"
|
26 |
-
os.makedirs(patient_directory + "T0/", exist_ok=True)
|
27 |
-
shutil.copy(input_path, patient_directory + "T0/" + splits[0] + "-t1gd." + extension)
|
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 |
-
try:
|
56 |
run_rads(config_filename='rads_config.ini')
|
|
|
|
|
|
|
|
|
57 |
except Exception as e:
|
58 |
print(e)
|
59 |
-
|
60 |
-
# rename and move final result
|
61 |
-
os.rename("./result/prediction-" + splits[0] + "/T0/" + splits[0] + "-t1gd_annotation-Tumor.nii.gz", "./prediction.nii.gz")
|
62 |
-
|
63 |
# Clean-up
|
64 |
if os.path.exists(patient_directory):
|
65 |
shutil.rmtree(patient_directory)
|
|
|
5 |
import traceback
|
6 |
|
7 |
|
8 |
+
def run_model(input_path: str, model_path: str, verbose: str = "info", task: str = "MRI_Meningioma", name: str = "Tumor"):
|
9 |
logging.basicConfig()
|
10 |
logging.getLogger().setLevel(logging.WARNING)
|
11 |
|
|
|
17 |
logging.getLogger().setLevel(logging.ERROR)
|
18 |
else:
|
19 |
raise ValueError("Unsupported verbose value provided:", verbose)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
|
21 |
+
# delete patient/result folder if they exist
|
22 |
+
if os.path.exists("./patient/"):
|
23 |
+
shutil.rmtree("./patient/")
|
24 |
+
if os.path.exists("./result/"):
|
25 |
+
shutil.rmtree("./result/")
|
26 |
+
|
27 |
+
try:
|
28 |
+
# create sequence folder, rename patient, and add to temporary patient directory
|
29 |
+
filename = input_path.split("/")[-1]
|
30 |
+
splits = filename.split(".")
|
31 |
+
extension = ".".join(splits[1:])
|
32 |
+
patient_directory = "./patient/"
|
33 |
+
os.makedirs(patient_directory + "T0/", exist_ok=True)
|
34 |
+
shutil.copy(input_path, patient_directory + "T0/" + splits[0] + "-t1gd." + extension)
|
35 |
+
|
36 |
+
# define output directory to save results
|
37 |
+
output_path = "./result/prediction-" + splits[0] + "/"
|
38 |
+
os.makedirs(output_path, exist_ok=True)
|
39 |
|
40 |
+
# Setting up the configuration file
|
41 |
+
rads_config = configparser.ConfigParser()
|
42 |
+
rads_config.add_section('Default')
|
43 |
+
rads_config.set('Default', 'task', 'neuro_diagnosis')
|
44 |
+
rads_config.set('Default', 'caller', '')
|
45 |
+
rads_config.add_section('System')
|
46 |
+
rads_config.set('System', 'gpu_id', "-1")
|
47 |
+
rads_config.set('System', 'input_folder', patient_directory)
|
48 |
+
rads_config.set('System', 'output_folder', output_path)
|
49 |
+
rads_config.set('System', 'model_folder', model_path)
|
50 |
+
rads_config.set('System', 'pipeline_filename', os.path.join(model_path, task, 'pipeline.json'))
|
51 |
+
rads_config.add_section('Runtime')
|
52 |
+
rads_config.set('Runtime', 'reconstruction_method', 'thresholding') # thresholding, probabilities
|
53 |
+
rads_config.set('Runtime', 'reconstruction_order', 'resample_first')
|
54 |
+
rads_config.set('Runtime', 'use_preprocessed_data', 'False')
|
55 |
|
56 |
+
with open("rads_config.ini", "w") as f:
|
57 |
+
rads_config.write(f)
|
58 |
|
59 |
+
# finally, run inference
|
60 |
+
from raidionicsrads.compute import run_rads
|
61 |
|
|
|
62 |
run_rads(config_filename='rads_config.ini')
|
63 |
+
|
64 |
+
# rename and move final result
|
65 |
+
os.rename("./result/prediction-" + splits[0] + "/T0/" + splits[0] + "-t1gd_annotation-" + name + ".nii.gz", "./prediction.nii.gz")
|
66 |
+
|
67 |
except Exception as e:
|
68 |
print(e)
|
69 |
+
|
|
|
|
|
|
|
70 |
# Clean-up
|
71 |
if os.path.exists(patient_directory):
|
72 |
shutil.rmtree(patient_directory)
|