| import gradio as gr |
| import tensorflow as tf |
| import numpy as np |
| import cv2 |
| from PIL import Image |
|
|
| |
| IMG_SIZE = 300 |
| CLASSES = ["BACTERIAL", "NORMAL", "VIRAL"] |
| MODEL_PATH = "DenseNet201Final.keras" |
| LAST_CONV_LAYER = "conv5_block32_concat" |
|
|
| |
| model = tf.keras.models.load_model(MODEL_PATH, compile=False) |
|
|
| |
| def grad_cam(model, img_array, layer_name): |
| grad_model = tf.keras.models.Model( |
| inputs=model.inputs, |
| outputs=[ |
| model.get_layer(layer_name).output, |
| model.output |
| ] |
| ) |
|
|
| with tf.GradientTape() as tape: |
| conv_outputs, preds = grad_model(img_array) |
|
|
| |
| if isinstance(preds, (list, tuple)): |
| preds = preds[0] |
|
|
| class_idx = tf.argmax(preds[0]) |
| loss = preds[0, class_idx] |
|
|
| grads = tape.gradient(loss, conv_outputs) |
| pooled_grads = tf.reduce_mean(grads, axis=(0, 1, 2)) |
|
|
| conv_outputs = conv_outputs[0] |
| heatmap = tf.reduce_sum(pooled_grads * conv_outputs, axis=-1) |
|
|
| heatmap = tf.maximum(heatmap, 0) |
| heatmap /= tf.reduce_max(heatmap) + 1e-10 |
|
|
| return heatmap.numpy(), int(class_idx) |
|
|
|
|
| |
| def predict_xray(image): |
| if image is None: |
| return None, "No image uploaded" |
|
|
| |
| img = np.array(image.convert("RGB")) |
| img_resized = cv2.resize(img, (IMG_SIZE, IMG_SIZE)) |
| img_norm = img_resized / 255.0 |
| input_img = tf.convert_to_tensor(img_norm[None, ...], dtype=tf.float32) |
|
|
|
|
| |
| preds = model.predict(input_img) |
| class_idx = np.argmax(preds) |
| confidence = np.max(preds) |
|
|
| label = f"{CLASSES[class_idx]} ({confidence:.2%})" |
|
|
| |
| heatmap, _ = grad_cam(model, input_img, LAST_CONV_LAYER) |
| heatmap = cv2.resize(heatmap, (IMG_SIZE, IMG_SIZE)) |
| heatmap = np.uint8(255 * heatmap) |
| colored_heatmap = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET) |
|
|
| superimposed = cv2.addWeighted( |
| colored_heatmap, 0.5, |
| np.uint8(img_resized), 0.5, |
| 0 |
| ) |
|
|
| return Image.fromarray(superimposed), label |
|
|
| |
| demo = gr.Interface( |
| fn=predict_xray, |
| inputs=gr.Image(type="pil", label="Upload Chest X-ray"), |
| outputs=[ |
| gr.Image(label="Grad-CAM Heatmap"), |
| gr.Textbox(label="Prediction") |
| ], |
| title="🫁 Chest X-ray Pneumonia Classifier", |
| description="DenseNet201-based model with Grad-CAM explainability", |
| ) |
|
|
| if __name__ == "__main__": |
| demo.launch(share = True) |
|
|