Update app.py
Browse files
app.py
CHANGED
|
@@ -33,21 +33,48 @@ def make_gradcam_heatmap(img_array, model):
|
|
| 33 |
|
| 34 |
return heatmap.numpy()
|
| 35 |
|
| 36 |
-
def
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
# Plain base64 without prefix
|
| 45 |
-
image_bytes = base64.b64decode(input_image)
|
| 46 |
img = Image.open(io.BytesIO(image_bytes)).convert('RGB')
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
img = img.resize((224, 224))
|
| 52 |
img_array = np.array(img) / 255.0
|
| 53 |
img_array = np.expand_dims(img_array, axis=0)
|
|
@@ -75,16 +102,48 @@ def predict(input_image):
|
|
| 75 |
|
| 76 |
return output_image, result_text
|
| 77 |
|
| 78 |
-
|
| 79 |
-
|
|
|
|
| 80 |
inputs=gr.Image(label="Upload Histopathology Image"),
|
| 81 |
outputs=[
|
| 82 |
gr.Image(label="Grad-CAM Visualization"),
|
| 83 |
gr.Textbox(label="Classification Result")
|
| 84 |
],
|
| 85 |
title="Bone Cancer Detection (Osteosarcoma)",
|
| 86 |
-
description="Upload an H&E stained histopathology image
|
| 87 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 88 |
)
|
| 89 |
|
| 90 |
-
demo.launch()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
|
| 34 |
return heatmap.numpy()
|
| 35 |
|
| 36 |
+
def predict_from_base64(base64_string):
|
| 37 |
+
try:
|
| 38 |
+
# Remove data URL prefix if present
|
| 39 |
+
if ',' in base64_string:
|
| 40 |
+
base64_string = base64_string.split(',')[1]
|
| 41 |
+
|
| 42 |
+
# Decode base64 to image
|
| 43 |
+
image_bytes = base64.b64decode(base64_string)
|
|
|
|
|
|
|
| 44 |
img = Image.open(io.BytesIO(image_bytes)).convert('RGB')
|
| 45 |
+
|
| 46 |
+
img = img.resize((224, 224))
|
| 47 |
+
img_array = np.array(img) / 255.0
|
| 48 |
+
img_array = np.expand_dims(img_array, axis=0)
|
| 49 |
+
|
| 50 |
+
predictions = model.predict(img_array)
|
| 51 |
+
pred_class = CLASS_NAMES[np.argmax(predictions[0])]
|
| 52 |
+
confidence = float(np.max(predictions[0])) * 100
|
| 53 |
+
|
| 54 |
+
result_text = f"Prediction: {pred_class}\nConfidence: {confidence:.2f}%\n\n"
|
| 55 |
+
result_text += "All Probabilities:\n"
|
| 56 |
+
for i, name in enumerate(CLASS_NAMES):
|
| 57 |
+
result_text += f" {name}: {predictions[0][i]*100:.2f}%\n"
|
| 58 |
+
|
| 59 |
+
try:
|
| 60 |
+
heatmap = make_gradcam_heatmap(img_array, model)
|
| 61 |
+
heatmap = cv2.resize(heatmap, (224, 224))
|
| 62 |
+
heatmap = np.uint8(255 * heatmap)
|
| 63 |
+
heatmap_colored = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET)
|
| 64 |
+
original = np.array(img)
|
| 65 |
+
superimposed = cv2.addWeighted(original, 0.6, heatmap_colored, 0.4, 0)
|
| 66 |
+
output_image = superimposed
|
| 67 |
+
except Exception as e:
|
| 68 |
+
output_image = np.array(img)
|
| 69 |
+
result_text += f"\n(Grad-CAM unavailable: {str(e)})"
|
| 70 |
+
|
| 71 |
+
return output_image, result_text
|
| 72 |
|
| 73 |
+
except Exception as e:
|
| 74 |
+
return None, f"Error: {str(e)}"
|
| 75 |
+
|
| 76 |
+
def predict_from_image(input_image):
|
| 77 |
+
img = Image.fromarray(input_image).convert('RGB')
|
| 78 |
img = img.resize((224, 224))
|
| 79 |
img_array = np.array(img) / 255.0
|
| 80 |
img_array = np.expand_dims(img_array, axis=0)
|
|
|
|
| 102 |
|
| 103 |
return output_image, result_text
|
| 104 |
|
| 105 |
+
# Two interfaces: one for browser (image upload), one for API (base64)
|
| 106 |
+
image_interface = gr.Interface(
|
| 107 |
+
fn=predict_from_image,
|
| 108 |
inputs=gr.Image(label="Upload Histopathology Image"),
|
| 109 |
outputs=[
|
| 110 |
gr.Image(label="Grad-CAM Visualization"),
|
| 111 |
gr.Textbox(label="Classification Result")
|
| 112 |
],
|
| 113 |
title="Bone Cancer Detection (Osteosarcoma)",
|
| 114 |
+
description="Upload an H&E stained histopathology image."
|
| 115 |
+
)
|
| 116 |
+
|
| 117 |
+
api_interface = gr.Interface(
|
| 118 |
+
fn=predict_from_base64,
|
| 119 |
+
inputs=gr.Textbox(label="Base64 Image String"),
|
| 120 |
+
outputs=[
|
| 121 |
+
gr.Image(label="Grad-CAM Visualization"),
|
| 122 |
+
gr.Textbox(label="Classification Result")
|
| 123 |
+
],
|
| 124 |
+
api_name="predict_base64"
|
| 125 |
+
)
|
| 126 |
+
|
| 127 |
+
demo = gr.TabbedInterface(
|
| 128 |
+
[image_interface, api_interface],
|
| 129 |
+
["Upload Image", "API (Base64)"]
|
| 130 |
)
|
| 131 |
|
| 132 |
+
demo.launch()
|
| 133 |
+
```
|
| 134 |
+
|
| 135 |
+
---
|
| 136 |
+
|
| 137 |
+
## What Changed:
|
| 138 |
+
|
| 139 |
+
1. **Two interfaces** — one for browser upload, one for API with base64
|
| 140 |
+
2. **New API endpoint** — `/predict_base64` accepts base64 text
|
| 141 |
+
3. **Browser still works** — Users can still upload images normally
|
| 142 |
+
|
| 143 |
+
---
|
| 144 |
+
|
| 145 |
+
## After Update, Change n8n HTTP Request1:
|
| 146 |
+
|
| 147 |
+
**URL:**
|
| 148 |
+
```
|
| 149 |
+
https://hixoop-model-v1.hf.space/gradio_api/call/predict_base64
|