|
|
import gradio as gr |
|
|
import numpy as np |
|
|
from tensorflow.keras.models import load_model |
|
|
from tensorflow.keras import backend as K |
|
|
from PIL import Image |
|
|
from huggingface_hub import hf_hub_download |
|
|
import cv2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def preprocess(img): |
|
|
img_gray = np.array(img.convert("L")) |
|
|
img_resized = cv2.resize(img_gray, (224, 224)) |
|
|
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8)) |
|
|
img_clahe = clahe.apply(img_resized) |
|
|
img_norm = img_clahe / 255.0 |
|
|
|
|
|
|
|
|
img_norm = np.expand_dims(img_norm, axis=-1) |
|
|
return img_norm |
|
|
|
|
|
from skimage import measure |
|
|
|
|
|
def remove_small_blobs(mask, min_size=50): |
|
|
labels = measure.label(mask) |
|
|
for region in measure.regionprops(labels): |
|
|
if region.area < min_size: |
|
|
mask[labels == region.label] = 0 |
|
|
return mask |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def dice_coef(y_true, y_pred): |
|
|
y_true = K.cast(y_true, 'float32') |
|
|
y_pred = K.cast(y_pred, 'float32') |
|
|
y_true_f = K.flatten(y_true) |
|
|
y_pred_f = K.flatten(y_pred) |
|
|
intersect = K.sum(y_true_f * y_pred_f) |
|
|
return (2. * intersect + K.epsilon()) / (K.sum(y_true_f) + K.sum(y_pred_f) + K.epsilon()) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
model = None |
|
|
|
|
|
def get_model(): |
|
|
global model |
|
|
if model is None: |
|
|
try: |
|
|
|
|
|
model_path = hf_hub_download( |
|
|
repo_id="yaraa11/brain-tumor-segmentation", |
|
|
filename="CNNSegmentation_model.keras" |
|
|
) |
|
|
model = load_model(model_path, custom_objects={'dice_coef': dice_coef}, compile=False) |
|
|
except Exception as e: |
|
|
print("Error loading model:", e) |
|
|
raise e |
|
|
return model |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def predict(img): |
|
|
model = get_model() |
|
|
|
|
|
|
|
|
orig_size = img.size |
|
|
|
|
|
|
|
|
img_processed = preprocess(img) |
|
|
x = np.expand_dims(img_processed, 0) |
|
|
|
|
|
|
|
|
pred = model.predict(x)[0] |
|
|
tumor_present = pred.max() > 0.7 |
|
|
|
|
|
if tumor_present: |
|
|
mask = (pred > 0.7).astype(np.uint8) * 255 |
|
|
mask = remove_small_blobs(mask, min_size=50) |
|
|
mask_img = Image.fromarray(mask.squeeze()).convert("L") |
|
|
|
|
|
|
|
|
mask_img = mask_img.resize(orig_size) |
|
|
|
|
|
|
|
|
red_overlay = Image.new("RGB", orig_size, (255, 0, 0)) |
|
|
overlay = img.convert("RGB") |
|
|
overlay.paste(red_overlay, (0, 0), mask_img) |
|
|
return "Tumor Detected", overlay |
|
|
else: |
|
|
return "No Tumor Detected", None |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
with gr.Blocks(title="Brain Tumor Segmentation") as demo: |
|
|
gr.Markdown("<h1 style='text-align:center'>Brain Tumor Segmentation</h1>") |
|
|
gr.Markdown("Upload a brain MRI scan, and the app will tell you if a tumor is present. If yes, it will show the segmented tumor mask.") |
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(): |
|
|
img_input = gr.Image(type="pil", label="Upload MRI Scan") |
|
|
submit_btn = gr.Button("Analyze Scan") |
|
|
with gr.Column(): |
|
|
output_text = gr.Textbox(label="Tumor Detection Result") |
|
|
output_image = gr.Image(label="Tumor Mask / Overlay") |
|
|
|
|
|
submit_btn.click( |
|
|
fn=predict, |
|
|
inputs=img_input, |
|
|
outputs=[output_text, output_image] |
|
|
) |
|
|
demo.launch() |
|
|
|
|
|
|
|
|
|