Spaces:
Sleeping
Sleeping
| #load relevant modules | |
| from stat import FILE_ATTRIBUTE_INTEGRITY_STREAM | |
| import eyepy as ep | |
| import matplotlib.pyplot as plt | |
| import os | |
| import pandas as pd | |
| from PIL import Image | |
| import numpy as np | |
| import torch | |
| import shutil | |
| from skimage import measure, segmentation, morphology, exposure | |
| from octolyzer.segment.sloseg import slo_inference, avo_inference, fov_inference | |
| from octolyzer.utils import generate_imgmask, generate_zonal_masks | |
| from octolyzer.measure.slo import feature_measurement, get_vessel_coords | |
| import octolyzer.utils as utils | |
| import gradio as gr | |
| import tempfile | |
| # Load models | |
| # SLO segmentation models | |
| slo_model = slo_inference.SLOSegmenter() | |
| # FOV segmentation models | |
| fov_model = fov_inference.FOVSegmenter() | |
| # AVO segmentation models | |
| avo_model = avo_inference.AVOSegmenter() | |
| def load_file(e2e_file): | |
| ''' | |
| read e2e file and return slo image as float | |
| ''' | |
| if e2e_file is None: | |
| return "**Error:** Please upload an image first." | |
| filetype = e2e_file.rsplit('.', 1)[1].lower() | |
| if filetype == "e2e": | |
| ep_obj = ep.import_heyex_e2e(e2e_file) | |
| return ep_obj.localizer.data.astype(float) | |
| else: | |
| return "**Error:** Unsupported filetype" | |
| def create_SLO_segmentation(slo): | |
| slo_vbinmap = slo_model.predict_img(slo) | |
| return slo_vbinmap | |
| def create_avo_segmentation(slo): | |
| slo_avimout, od_centre = avo_model.predict_img(slo, location="macula") | |
| return slo_avimout, od_centre | |
| def plot_SLO_segmentation(slo, slo_vbinmap): | |
| # Assuming you have slo and slo_vbinmap from your experiment | |
| fig, ax = plt.subplots(1, 1, figsize=(8, 8)) | |
| # Display the SLO image as background | |
| ax.imshow(slo, cmap='gray') | |
| # Create a colored overlay for the binary vessel map | |
| # Generate RGBA mask with red channel (cmap=0) for vessels | |
| vessel_overlay = generate_imgmask(slo_vbinmap) # Red vessels | |
| ax.imshow(vessel_overlay, alpha=0.6) | |
| ax.set_title('SLO with Binary Vessel Overlay') | |
| ax.axis('off') | |
| return fig | |
| def plot_avo_segmentation(slo, slo_avimout): | |
| # Assuming you have slo and slo_vbinmap from your experiment | |
| fig, ax = plt.subplots(1, 1, figsize=(8, 8)) | |
| # Display the SLO image as background | |
| ax.imshow(slo, cmap='gray') | |
| # Create a colored overlay for the binary vessel map | |
| # Generate RGBA mask with red channel (cmap=0) for vessels | |
| avoimout_save = 191*slo_avimout[...,0] + 127*slo_avimout[...,2] + 255*slo_avimout[...,1] | |
| #vessel_overlay = generate_imgmask(slo_avimout[...,2]) # Red vessels | |
| ax.imshow(avoimout_save, alpha=0.6) | |
| ax.set_title('SLO with Artery / Veins / Optic Nerve Overlay') | |
| ax.axis('off') | |
| return fig | |
| def features(slo, od_centre, slo_vbinmap, slo_avimout): | |
| img_shape = slo.shape | |
| _, N = img_shape | |
| od_radius = None #macula centred map | |
| location = "Macula" | |
| scale = 1 | |
| slo_dict = {} | |
| slo_keys = ["binary", "artery", "vein"] | |
| masks = generate_zonal_masks((N,N), od_radius, od_centre, location) | |
| artery_vbinmap, vein_vbinmap = slo_avimout[...,0], slo_avimout[...,2] | |
| od_mask = slo_avimout[...,1] | |
| for v_map, v_type in zip([slo_vbinmap, artery_vbinmap, vein_vbinmap], slo_keys): | |
| vcoords = get_vessel_coords.generate_vessel_skeleton(v_map, od_mask, od_centre, min_length=10) | |
| slo_dict[v_type] = feature_measurement.vessel_metrics(v_map, vcoords, masks, scale=scale, vessel_type=v_type) | |
| slo_df = utils.nested_dict_to_df(slo_dict).reset_index() | |
| slo_df = slo_df.rename({"level_0":"vessel_map", "level_1":"zone"}, axis=1, inplace=False) | |
| reorder_cols = ["vessel_map", "zone", "fractal_dimension", "vessel_density", "average_global_calibre", | |
| "average_local_calibre", "tortuosity_density", "tortuosity_distance", "CRAE_Knudtson", "CRVE_Knudtson"] | |
| slo_df = slo_df[reorder_cols] | |
| return slo_df | |
| def predict(e2e_file): | |
| slo = load_file(e2e_file) | |
| all_vessels = create_SLO_segmentation(slo) | |
| AVO, OD_centre = create_avo_segmentation(slo) | |
| all_vessel_plot = plot_SLO_segmentation(slo, all_vessels) | |
| AVO_plot = plot_avo_segmentation(slo, AVO) | |
| slo_df = features(slo, OD_centre, all_vessels, AVO) | |
| csv_file = tempfile.NamedTemporaryFile(delete=False, suffix='.csv') | |
| slo_df.to_csv(csv_file.name, index=False) | |
| csv_file.close() | |
| return all_vessel_plot, AVO_plot, slo_df, Image.fromarray(slo), csv_file.name | |
| # Create Gradio Interface | |
| with gr.Blocks() as demo: | |
| gr.Markdown( | |
| """ | |
| # Automated Retinal Vascular Morphology Quantification from SLO images | |
| Upload a Heidelberg Spectralis .E2E file to automatically segment and assess vessel metrics | |
| **Accepted formats:** E2E | |
| **Scan type:** Only macular centred scans accepted. | |
| **Disclaimer:** This is a research tool and not intended for clinical use. | |
| """ | |
| ) | |
| with gr.Row(): | |
| with gr.Column(): | |
| image_input = gr.File( | |
| label="Upload e2e Image" | |
| ) | |
| #predict_btn = gr.Button("🔍 Analyze Image", variant="primary") | |
| with gr.Row(): | |
| with gr.Column(): | |
| slo_image = gr.Image(label = "SLO image to be analysed") | |
| with gr.Column(): | |
| plot_output_1 = gr.Plot(label = "segmentation map of all vessels") | |
| with gr.Column(): | |
| plot_output_2 = gr.Plot(label = "segmentation map of arteries / veins / optic nerves") | |
| with gr.Row(): | |
| with gr.Column(): | |
| dataframe_output = gr.Dataframe(label="Vessel Metrics", wrap=True) | |
| csv_download = gr.File(label="Download CSV", file_count="single") | |
| image_input.upload( | |
| fn=predict, | |
| inputs=image_input, | |
| outputs=[plot_output_1, plot_output_2, dataframe_output, slo_image, csv_download] | |
| ) | |
| gr.Markdown( | |
| """ | |
| --- | |
| ### About this tool | |
| This tool is adapted from Octolyzer, a fully automatic toolkit for segmentation and feature extracting in optical coherence tomography and scanning laser ophthalmoscopy data | |
| **Citation:** https://arxiv.org/abs/2407.14128 and https://github.com/jaburke166/OCTolyzer | |
| **License:** GPL-3.0 license | |
| """ | |
| ) | |
| # Launch | |
| if __name__ == "__main__": | |
| demo.launch() |