Skip to content

Commit

Permalink
Merge pull request #2 from andreped/dev
Browse files Browse the repository at this point in the history
Implemented working demo
  • Loading branch information
andreped committed Jun 5, 2023
2 parents 5237ee9 + 6f7cbfb commit bd4be62
Show file tree
Hide file tree
Showing 9 changed files with 120 additions and 26 deletions.
9 changes: 9 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1 +1,10 @@
venv/
*__pycache__/
resources/
*.DS_Store
*.nii
*.nii.gz
*.nrrd
*.obj
*log.csv
*.ini
2 changes: 1 addition & 1 deletion .github/workflows/filesize.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on: # or directly `on: [push]` to run the action on every push on
workflow_dispatch:

jobs:
sync-to-hub:
check-filesize:
runs-on: ubuntu-latest
steps:
- name: Check large files
Expand Down
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,10 @@
venv/
*__pycache__/
resources/
*.DS_Store
*.nii
*.nii.gz
*.nrrd
*.obj
*log.csv
*.ini
3 changes: 3 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ COPY --chown=user . $HOME/app
RUN wget "https://github.com/raidionics/Raidionics-models/releases/download/1.2.0/Raidionics-MRI_Meningioma-ONNX-v12.zip" && \
unzip "Raidionics-MRI_Meningioma-ONNX-v12.zip" && mkdir -p resources/models/ && mv MRI_Meningioma/ resources/models/MRI_Meningioma/

# Download test sample
RUN wget "https://github.com/andreped/neukit/releases/download/test-data/RegLib_C01_2.nii.gz"

# Download test sample
RUN pip install gdown && gdown "https://drive.google.com/uc?id=1shjSrFjS4PHE5sTku30PZTLPZpGu24o3"

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ The software will be made openly available on Hugging Face spaces very soon. Sta
For development of this software, follow these steps to build the docker image and run the app through it:

```
docker build -t neukit ..
docker build -t neukit .
docker run -it -p 7860:7860 neukit
```

Expand Down
7 changes: 2 additions & 5 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,11 @@
def main():
print("Launching demo...")

# cwd = "/Users/andreped/workspace/livermask/" # local testing -> macOS
# cwd = "/Users/andreped/workspace/neukit/" # local testing -> macOS
cwd = "/home/user/app/" # production -> docker

model_name = "model.h5" # assumed to lie in `cwd` directory
class_name = "parenchyma"

# initialize and run app
app = WebUI(model_name=model_name, class_name=class_name, cwd=cwd)
app = WebUI(cwd=cwd)
app.run()


Expand Down
45 changes: 27 additions & 18 deletions neukit/gui.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import gradio as gr
from .utils import load_ct_to_numpy, load_pred_volume_to_numpy
from .compute import run_model
from .convert import nifti_to_glb
from .utils import load_ct_to_numpy, load_pred_volume_to_numpy, nifti_to_glb
from .inference import run_model


class WebUI:
def __init__(self, model_name:str = None, class_name:str = None, cwd:str = None):
def __init__(self, model_name:str = None, class_name:str = "meningioma", cwd:str = "/home/user/app/"):
# global states
self.images = []
self.pred_images = []

# @TODO: This should be dynamically set based on chosen volume size
self.nb_slider_items = 100
self.nb_slider_items = 150

self.model_name = model_name
self.class_name = class_name
Expand All @@ -22,7 +21,8 @@ def __init__(self, model_name:str = None, class_name:str = None, cwd:str = None)
self.volume_renderer = gr.Model3D(
clear_color=[0.0, 0.0, 0.0, 0.0],
label="3D Model",
visible=True
visible=True,
elem_id="model-3d",
).style(height=512)

def combine_ct_and_seg(self, img, pred):
Expand All @@ -31,12 +31,13 @@ def combine_ct_and_seg(self, img, pred):
def upload_file(self, file):
return file.name

def load_mesh(self, mesh_file_name, model_name):
def load_mesh(self, mesh_file_name):
path = mesh_file_name.name
run_model(path, model_name)
nifti_to_glb("prediction-livermask.nii")
run_model(path, model_path=self.cwd + "resources/models/")
nifti_to_glb("prediction.nii.gz")

self.images = load_ct_to_numpy(path)
self.pred_images = load_pred_volume_to_numpy("./prediction-livermask.nii")
self.pred_images = load_pred_volume_to_numpy("./prediction.nii.gz")
self.slider = self.slider.update(value=2)
return "./prediction.obj"

Expand All @@ -47,37 +48,45 @@ def get_img_pred_pair(self, k):
return out

def run(self):
with gr.Blocks() as demo:
css="""
#model-3d {
height: 512px;
}
#model-2d {
height: 512px;
margin: auto;
}
"""
with gr.Blocks(css=css) as demo:

with gr.Row().style(equal_height=True):
with gr.Row():
file_output = gr.File(
file_types=[".nii", ".nii.nz"],
file_count="single"
).style(full_width=False, size="sm")
file_output.upload(self.upload_file, file_output, file_output)

run_btn = gr.Button("Run analysis").style(full_width=False, size="sm")
run_btn.click(
fn=lambda x: self.load_mesh(x, model_name=self.cwd + self.model_name),
fn=lambda x: self.load_mesh(x),
inputs=file_output,
outputs=self.volume_renderer
)

with gr.Row().style(equal_height=True):
with gr.Row():
gr.Examples(
examples=[self.cwd + "test-volume.nii"],
examples=[self.cwd + "RegLib_C01_2.nii.gz"],
inputs=file_output,
outputs=file_output,
fn=self.upload_file,
cache_examples=True,
)

with gr.Row().style(equal_height=True):
with gr.Row():
with gr.Box():
image_boxes = []
for i in range(self.nb_slider_items):
visibility = True if i == 1 else False
t = gr.AnnotatedImage(visible=visibility)\
t = gr.AnnotatedImage(visible=visibility, elem_id="model-2d")\
.style(color_map={self.class_name: "#ffae00"}, height=512, width=512)
image_boxes.append(t)

Expand Down
67 changes: 67 additions & 0 deletions neukit/inference.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import os
import shutil
import configparser
import logging
import traceback


def run_model(input_path: str, model_path: str, verbose: str = "info", task: str = "MRI_Meningioma"):
logging.basicConfig()
logging.getLogger().setLevel(logging.WARNING)

if verbose == 'debug':
logging.getLogger().setLevel(logging.DEBUG)
elif verbose == 'info':
logging.getLogger().setLevel(logging.INFO)
elif verbose == 'error':
logging.getLogger().setLevel(logging.ERROR)
else:
raise ValueError("Unsupported verbose value provided:", verbose)

# create sequence folder, rename patient, and add to temporary patient directory
filename = input_path.split("/")[-1]
splits = filename.split(".")
extension = ".".join(splits[1:])
patient_directory = "./patient/"
os.makedirs(patient_directory + "T0/", exist_ok=True)
shutil.copy(input_path, patient_directory + "T0/" + splits[0] + "-t1gd." + extension)

# define output directory to save results
output_path = "./result/prediction-" + splits[0] + "/"
os.makedirs(output_path, exist_ok=True)

# Setting up the configuration file
rads_config = configparser.ConfigParser()
rads_config.add_section('Default')
rads_config.set('Default', 'task', 'neuro_diagnosis')
rads_config.set('Default', 'caller', '')
rads_config.add_section('System')
rads_config.set('System', 'gpu_id', "-1")
rads_config.set('System', 'input_folder', patient_directory)
rads_config.set('System', 'output_folder', output_path)
rads_config.set('System', 'model_folder', model_path)
rads_config.set('System', 'pipeline_filename', os.path.join(model_path, task, 'pipeline.json'))
rads_config.add_section('Runtime')
rads_config.set('Runtime', 'reconstruction_method', 'thresholding') # thresholding, probabilities
rads_config.set('Runtime', 'reconstruction_order', 'resample_first')
rads_config.set('Runtime', 'use_preprocessed_data', 'False')

with open("rads_config.ini", "w") as f:
rads_config.write(f)

# finally, run inference
from raidionicsrads.compute import run_rads

try:
run_rads(config_filename='rads_config.ini')
except Exception as e:
print(e)

# rename and move final result
os.rename("./result/prediction-" + splits[0] + "/T0/" + splits[0] + "-t1gd_annotation-Tumor.nii.gz", "./prediction.nii.gz")

# Clean-up
if os.path.exists(patient_directory):
shutil.rmtree(patient_directory)
if os.path.exists(output_path):
shutil.rmtree(output_path)
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
raidionicsrads @ https://github.com/dbouget/raidionics_rads_lib/releases/download/v1.1.0/raidionicsrads-1.1.0-py3-none-manylinux1_x86_64.whl
onnxruntime-gpu==1.12.1
#raidionicsrads @ https://github.com/dbouget/raidionics_rads_lib/releases/download/v1.1.0/raidionicsrads-1.1.0-py3-none-macosx_10_15_x86_64.whl
gradio==3.32.0

0 comments on commit bd4be62

Please sign in to comment.