import gradio as gr from tensorflow import keras import numpy as np from PIL import Image import cv2 import tensorflow as tf import base64 import io model = keras.models.load_model('my_model (2).h5') CLASS_NAMES = ['Non-Tumor', 'Non-Viable-Tumor', 'Viable', 'viable: non-viable'] def make_gradcam_heatmap(img_array, model): last_conv_layer = model.get_layer('last_conv_layer') grad_model = tf.keras.models.Model( [model.inputs], [last_conv_layer.output, model.output] ) with tf.GradientTape() as tape: conv_outputs, predictions = grad_model(img_array) pred_index = tf.argmax(predictions[0]) class_channel = predictions[:, pred_index] grads = tape.gradient(class_channel, conv_outputs) pooled_grads = tf.reduce_mean(grads, axis=(0, 1, 2)) conv_outputs = conv_outputs[0] heatmap = conv_outputs @ pooled_grads[..., tf.newaxis] heatmap = tf.squeeze(heatmap) heatmap = tf.maximum(heatmap, 0) / (tf.math.reduce_max(heatmap) + 1e-8) return heatmap.numpy() def predict_from_base64(base64_string): try: if ',' in base64_string: base64_string = base64_string.split(',')[1] image_bytes = base64.b64decode(base64_string) img = Image.open(io.BytesIO(image_bytes)).convert('RGB') img = img.resize((224, 224)) img_array = np.array(img) / 255.0 img_array = np.expand_dims(img_array, axis=0) predictions = model.predict(img_array) pred_class = CLASS_NAMES[np.argmax(predictions[0])] confidence = float(np.max(predictions[0])) * 100 result_text = f"Prediction: {pred_class}\nConfidence: {confidence:.2f}%\n\n" result_text += "All Probabilities:\n" for i, name in enumerate(CLASS_NAMES): result_text += f" {name}: {predictions[0][i]*100:.2f}%\n" try: heatmap = make_gradcam_heatmap(img_array, model) heatmap = cv2.resize(heatmap, (224, 224)) heatmap = np.uint8(255 * heatmap) heatmap_colored = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET) original = np.array(img) superimposed = cv2.addWeighted(original, 0.6, heatmap_colored, 0.4, 0) output_image = superimposed except Exception as e: output_image = np.array(img) result_text += f"\n(Grad-CAM unavailable: {str(e)})" return output_image, result_text except Exception as e: return None, f"Error: {str(e)}" def predict_from_image(input_image): img = Image.fromarray(input_image).convert('RGB') img = img.resize((224, 224)) img_array = np.array(img) / 255.0 img_array = np.expand_dims(img_array, axis=0) predictions = model.predict(img_array) pred_class = CLASS_NAMES[np.argmax(predictions[0])] confidence = float(np.max(predictions[0])) * 100 result_text = f"Prediction: {pred_class}\nConfidence: {confidence:.2f}%\n\n" result_text += "All Probabilities:\n" for i, name in enumerate(CLASS_NAMES): result_text += f" {name}: {predictions[0][i]*100:.2f}%\n" try: heatmap = make_gradcam_heatmap(img_array, model) heatmap = cv2.resize(heatmap, (224, 224)) heatmap = np.uint8(255 * heatmap) heatmap_colored = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET) original = np.array(img) superimposed = cv2.addWeighted(original, 0.6, heatmap_colored, 0.4, 0) output_image = superimposed except Exception as e: output_image = np.array(img) result_text += f"\n(Grad-CAM unavailable: {str(e)})" return output_image, result_text image_interface = gr.Interface( fn=predict_from_image, inputs=gr.Image(label="Upload Histopathology Image"), outputs=[ gr.Image(label="Grad-CAM Visualization"), gr.Textbox(label="Classification Result") ], title="Bone Cancer Detection (Osteosarcoma)", description="Upload an H&E stained histopathology image." ) api_interface = gr.Interface( fn=predict_from_base64, inputs=gr.Textbox(label="Base64 Image String"), outputs=[ gr.Image(label="Grad-CAM Visualization"), gr.Textbox(label="Classification Result") ], api_name="predict_base64" ) demo = gr.TabbedInterface( [image_interface, api_interface], ["Upload Image", "API (Base64)"] ) demo.launch()