From 366c806e795033d0964b38666075b1d864713964 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Pedersen?= Date: Fri, 21 Jun 2024 12:19:21 +0200 Subject: [PATCH 1/4] Upgraded gradio==4.29.0 --- demo/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo/requirements.txt b/demo/requirements.txt index 3ee9ebd..f6f1022 100644 --- a/demo/requirements.txt +++ b/demo/requirements.txt @@ -1,2 +1,2 @@ raidionicsrads@git+https://github.com/dbouget/raidionics_rads_lib -gradio==3.50.2 +gradio==4.29.0 From 4146752481827c547bd64b2b138c87b63c125634 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Pedersen?= Date: Fri, 21 Jun 2024 12:29:02 +0200 Subject: [PATCH 2/4] Added support to download prediction --- demo/src/gui.py | 55 +++++++++++++++++++++++++++++++------------ demo/src/inference.py | 6 ++++- 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/demo/src/gui.py b/demo/src/gui.py index 74df10d..72ae356 100644 --- a/demo/src/gui.py +++ b/demo/src/gui.py @@ -59,7 +59,8 @@ def __init__( visible=True, elem_id="model-3d", camera_position=[90, 180, 768], - ).style(height=512) + height=512, + ) def set_class_name(self, value): LOGGER.info(f"Changed task to: {value}") @@ -75,22 +76,31 @@ def upload_file(self, file): def process(self, mesh_file_name): path = mesh_file_name.name + curr = path.split("/")[-1] + self.extension = ".".join(curr.split(".")[1:]) + self.filename = curr.split(".")[0] + "-" + self.class_names[self.class_name] run_model( path, model_path=os.path.join(self.cwd, "resources/models/"), task=self.class_names[self.class_name], name=self.result_names[self.class_name], + output_filename=self.filename + "." + self.extension ) LOGGER.info("Converting prediction NIfTI to OBJ...") - nifti_to_obj("prediction.nii.gz") + nifti_to_obj(path=self.filename + "." + self.extension) LOGGER.info("Loading CT to numpy...") self.images = load_ct_to_numpy(path) LOGGER.info("Loading prediction volume to numpy..") - self.pred_images = load_pred_volume_to_numpy("./prediction.nii.gz") + self.pred_images = load_pred_volume_to_numpy(self.filename + "." + self.extension) return "./prediction.obj" + + def download_prediction(self): + if (not self.filename) or (not self.extension): + LOGGER.error("The prediction is not available or ready to download. Wait until the result is available in the 3D viewer.") + return self.filename + "." + self.extension def get_img_pred_pair(self, k): k = int(k) @@ -98,7 +108,6 @@ def get_img_pred_pair(self, k): self.combine_ct_and_seg(self.images[k], self.pred_images[k]), visible=True, elem_id="model-2d", - ).style( color_map={self.class_name: "#ffae00"}, height=512, width=512, @@ -122,9 +131,7 @@ def run(self): autoscroll=True, elem_id="logs", show_copy_button=True, - scroll_to_output=False, container=True, - line_breaks=True, ) demo.load(read_logs, None, logs, every=1) @@ -160,7 +167,7 @@ def run(self): label="Task", info="Which structure to segment.", multiselect=False, - size="sm", + scale=1.0, ) model_selector.input( fn=lambda x: self.set_class_name(x), @@ -173,16 +180,33 @@ def run(self): "Run analysis", variant="primary", elem_id="run-button", - ).style( - full_width=False, + #scale=1.0, + # size=1.0, size="lg", ) + #.style( + # full_width=False, + # size="lg", + #) run_btn.click( fn=lambda x: self.process(x), inputs=file_output, outputs=self.volume_renderer, ) + download_btn = gr.DownloadButton( + "Download the result as NIfTI", + visible=True, + variant="secondary", + # scale=1.0, + size="sm", + ) + download_btn.click( + fn=self.download_prediction, + inputs=None, + outputs=download_btn, + ) + with gr.Row(): gr.Examples( examples=[ @@ -202,16 +226,17 @@ def run(self): ) with gr.Row(): - with gr.Box(): + with gr.Group(): #gr.Box(): with gr.Column(): # create dummy image to be replaced by loaded images t = gr.AnnotatedImage( visible=True, elem_id="model-2d" - ).style( - color_map={self.class_name: "#ffae00"}, - height=512, - width=512, ) + #.style( + # color_map={self.class_name: "#ffae00"}, + # height=512, + # width=512, + #) self.slider.input( self.get_img_pred_pair, @@ -221,7 +246,7 @@ def run(self): self.slider.render() - with gr.Box(): + with gr.Group(): #gr.Box(): self.volume_renderer.render() # sharing app publicly -> share=True: diff --git a/demo/src/inference.py b/demo/src/inference.py index 5d3774c..34e495d 100644 --- a/demo/src/inference.py +++ b/demo/src/inference.py @@ -11,6 +11,7 @@ def run_model( verbose: str = "info", task: str = "CT_Airways", name: str = "Airways", + output_filename: str = None, ): if verbose == "debug": logging.getLogger().setLevel(logging.DEBUG) @@ -27,6 +28,9 @@ def run_model( if os.path.exists("./result/"): shutil.rmtree("./result/") + if output_filename is None: + raise ValueError("Please, set output_filename.") + patient_directory = "" output_path = "" try: @@ -84,7 +88,7 @@ def run_model( + "-t1gd_annotation-" + name + ".nii.gz", - "./prediction.nii.gz", + output_filename, ) # Clean-up if os.path.exists(patient_directory): From 5ad5add8e9ded48a8d3d044f91cb0359403e8877 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Pedersen?= Date: Fri, 21 Jun 2024 12:49:59 +0200 Subject: [PATCH 3/4] Fixed CSS styling after gradio update --- demo/src/css_style.py | 6 +++++- demo/src/gui.py | 38 ++++++++++++++------------------------ 2 files changed, 19 insertions(+), 25 deletions(-) diff --git a/demo/src/css_style.py b/demo/src/css_style.py index f6a7d7a..2573f56 100644 --- a/demo/src/css_style.py +++ b/demo/src/css_style.py @@ -9,8 +9,12 @@ #upload { height: 110px; } +#download { +height: 47px; +width: 150px; +} #run-button { -height: 110px; +height: 47px; width: 150px; } #toggle-button { diff --git a/demo/src/gui.py b/demo/src/gui.py index 72ae356..ce63059 100644 --- a/demo/src/gui.py +++ b/demo/src/gui.py @@ -126,8 +126,8 @@ def run(self): placeholder="\n" * 16, label="Logs", info="Verbose from inference will be displayed below.", - lines=38, - max_lines=38, + lines=36, + max_lines=36, autoscroll=True, elem_id="logs", show_copy_button=True, @@ -137,7 +137,7 @@ def run(self): with gr.Column(): with gr.Row(): - with gr.Column(scale=0.2, min_width=150): + with gr.Column(scale=1, min_width=150): sidebar_state = gr.State(True) btn_toggle_sidebar = gr.Button( @@ -156,7 +156,7 @@ def run(self): btn_clear_logs.click(flush_logs, [], []) file_output = gr.File( - file_count="single", elem_id="upload" + file_count="single", elem_id="upload", scale=3, ) file_output.upload( self.upload_file, file_output, file_output @@ -167,7 +167,7 @@ def run(self): label="Task", info="Which structure to segment.", multiselect=False, - scale=1.0, + scale=1, ) model_selector.input( fn=lambda x: self.set_class_name(x), @@ -175,19 +175,12 @@ def run(self): outputs=None, ) - with gr.Column(scale=0.2, min_width=150): + with gr.Column(scale=1, min_width=150): run_btn = gr.Button( "Run analysis", variant="primary", elem_id="run-button", - #scale=1.0, - # size=1.0, - size="lg", ) - #.style( - # full_width=False, - # size="lg", - #) run_btn.click( fn=lambda x: self.process(x), inputs=file_output, @@ -195,11 +188,10 @@ def run(self): ) download_btn = gr.DownloadButton( - "Download the result as NIfTI", + "Download prediction", visible=True, variant="secondary", - # scale=1.0, - size="sm", + elem_id="download", ) download_btn.click( fn=self.download_prediction, @@ -226,18 +218,16 @@ def run(self): ) with gr.Row(): - with gr.Group(): #gr.Box(): + with gr.Group(): with gr.Column(): # create dummy image to be replaced by loaded images t = gr.AnnotatedImage( - visible=True, elem_id="model-2d" + visible=True, + elem_id="model-2d", + color_map={self.class_name: "#ffae00"}, + #height=512, + #width=512, ) - #.style( - # color_map={self.class_name: "#ffae00"}, - # height=512, - # width=512, - #) - self.slider.input( self.get_img_pred_pair, self.slider, From 8291c90c73f2b3ce620371e5dee59f4b46f0c22b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Pedersen?= Date: Fri, 21 Jun 2024 12:52:07 +0200 Subject: [PATCH 4/4] Linted code --- demo/src/gui.py | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/demo/src/gui.py b/demo/src/gui.py index ce63059..2686eaf 100644 --- a/demo/src/gui.py +++ b/demo/src/gui.py @@ -78,13 +78,15 @@ def process(self, mesh_file_name): path = mesh_file_name.name curr = path.split("/")[-1] self.extension = ".".join(curr.split(".")[1:]) - self.filename = curr.split(".")[0] + "-" + self.class_names[self.class_name] + self.filename = ( + curr.split(".")[0] + "-" + self.class_names[self.class_name] + ) run_model( path, model_path=os.path.join(self.cwd, "resources/models/"), task=self.class_names[self.class_name], name=self.result_names[self.class_name], - output_filename=self.filename + "." + self.extension + output_filename=self.filename + "." + self.extension, ) LOGGER.info("Converting prediction NIfTI to OBJ...") nifti_to_obj(path=self.filename + "." + self.extension) @@ -93,13 +95,17 @@ def process(self, mesh_file_name): self.images = load_ct_to_numpy(path) LOGGER.info("Loading prediction volume to numpy..") - self.pred_images = load_pred_volume_to_numpy(self.filename + "." + self.extension) + self.pred_images = load_pred_volume_to_numpy( + self.filename + "." + self.extension + ) return "./prediction.obj" - + def download_prediction(self): if (not self.filename) or (not self.extension): - LOGGER.error("The prediction is not available or ready to download. Wait until the result is available in the 3D viewer.") + LOGGER.error( + "The prediction is not available or ready to download. Wait until the result is available in the 3D viewer." + ) return self.filename + "." + self.extension def get_img_pred_pair(self, k): @@ -156,7 +162,9 @@ def run(self): btn_clear_logs.click(flush_logs, [], []) file_output = gr.File( - file_count="single", elem_id="upload", scale=3, + file_count="single", + elem_id="upload", + scale=3, ) file_output.upload( self.upload_file, file_output, file_output @@ -225,8 +233,8 @@ def run(self): visible=True, elem_id="model-2d", color_map={self.class_name: "#ffae00"}, - #height=512, - #width=512, + # height=512, + # width=512, ) self.slider.input( self.get_img_pred_pair, @@ -236,7 +244,7 @@ def run(self): self.slider.render() - with gr.Group(): #gr.Box(): + with gr.Group(): # gr.Box(): self.volume_renderer.render() # sharing app publicly -> share=True: