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)
|