Update app.py
Browse files
app.py
CHANGED
|
@@ -17,7 +17,7 @@ except Exception as e:
|
|
| 17 |
model = tf.keras.Model(inputs, outputs)
|
| 18 |
|
| 19 |
# ==============================================================================
|
| 20 |
-
# --- Grad-CAM Heatmap Generation Functions (
|
| 21 |
# ==============================================================================
|
| 22 |
|
| 23 |
def get_last_conv_layer_name(model):
|
|
@@ -28,25 +28,28 @@ def get_last_conv_layer_name(model):
|
|
| 28 |
raise ValueError("Could not find a conv layer in the model")
|
| 29 |
|
| 30 |
def make_gradcam_heatmap(img_array, model, last_conv_layer_name):
|
| 31 |
-
"""Generates the Grad-CAM heatmap
|
| 32 |
grad_model = tf.keras.models.Model(
|
| 33 |
model.inputs, [model.get_layer(last_conv_layer_name).output, model.output]
|
| 34 |
)
|
| 35 |
with tf.GradientTape() as tape:
|
| 36 |
last_conv_layer_output, preds = grad_model([img_array], training=False)
|
| 37 |
|
| 38 |
-
# <-- THE ONLY FIX: A robust check that preserves your original logic.
|
| 39 |
-
# This handles tensor shape variations without changing the code's structure.
|
| 40 |
preds_tensor = preds[0]
|
| 41 |
if tf.rank(preds_tensor) > 1:
|
| 42 |
-
# If tensor is 2D (e.g., shape=(1,1)), slice it like your original code.
|
| 43 |
class_channel = preds_tensor[:, 0]
|
| 44 |
else:
|
| 45 |
-
# If tensor is 1D (e.g., shape=(1,)), use it directly.
|
| 46 |
class_channel = preds_tensor
|
| 47 |
|
| 48 |
grads = tape.gradient(class_channel, last_conv_layer_output)
|
| 49 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
pooled_grads = tf.reduce_mean(grads, axis=(0, 1, 2))
|
| 51 |
last_conv_layer_output = last_conv_layer_output[0]
|
| 52 |
heatmap = last_conv_layer_output @ pooled_grads[..., tf.newaxis]
|
|
@@ -55,13 +58,11 @@ def make_gradcam_heatmap(img_array, model, last_conv_layer_name):
|
|
| 55 |
return heatmap.numpy()
|
| 56 |
|
| 57 |
def superimpose_gradcam(original_img_pil, heatmap):
|
| 58 |
-
"""Overlays the heatmap on the original image
|
| 59 |
original_img = np.array(original_img_pil)
|
| 60 |
heatmap = cv2.resize(heatmap, (original_img.shape[1], original_img.shape[0]))
|
| 61 |
heatmap = np.uint8(255 * heatmap)
|
| 62 |
-
# Restored to COLORMAP_JET as in your code.
|
| 63 |
heatmap = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET)
|
| 64 |
-
# Removed the blur and restored your original transparency.
|
| 65 |
superimposed_img = cv2.addWeighted(original_img, 0.6, heatmap, 0.4, 0)
|
| 66 |
return Image.fromarray(superimposed_img)
|
| 67 |
|
|
|
|
| 17 |
model = tf.keras.Model(inputs, outputs)
|
| 18 |
|
| 19 |
# ==============================================================================
|
| 20 |
+
# --- Grad-CAM Heatmap Generation Functions (with safety check restored) ---
|
| 21 |
# ==============================================================================
|
| 22 |
|
| 23 |
def get_last_conv_layer_name(model):
|
|
|
|
| 28 |
raise ValueError("Could not find a conv layer in the model")
|
| 29 |
|
| 30 |
def make_gradcam_heatmap(img_array, model, last_conv_layer_name):
|
| 31 |
+
"""Generates the Grad-CAM heatmap with a stability check."""
|
| 32 |
grad_model = tf.keras.models.Model(
|
| 33 |
model.inputs, [model.get_layer(last_conv_layer_name).output, model.output]
|
| 34 |
)
|
| 35 |
with tf.GradientTape() as tape:
|
| 36 |
last_conv_layer_output, preds = grad_model([img_array], training=False)
|
| 37 |
|
|
|
|
|
|
|
| 38 |
preds_tensor = preds[0]
|
| 39 |
if tf.rank(preds_tensor) > 1:
|
|
|
|
| 40 |
class_channel = preds_tensor[:, 0]
|
| 41 |
else:
|
|
|
|
| 42 |
class_channel = preds_tensor
|
| 43 |
|
| 44 |
grads = tape.gradient(class_channel, last_conv_layer_output)
|
| 45 |
|
| 46 |
+
# <-- FIX: The critical safety check is restored here.
|
| 47 |
+
# This prevents the "None to a Tensor" crash without changing the logic.
|
| 48 |
+
if grads is None:
|
| 49 |
+
print("Warning: Gradient is None. Cannot compute heatmap for this image. Returning a blank map.")
|
| 50 |
+
h, w = last_conv_layer_output.shape[1:3]
|
| 51 |
+
return np.zeros((h, w), dtype=np.float32)
|
| 52 |
+
|
| 53 |
pooled_grads = tf.reduce_mean(grads, axis=(0, 1, 2))
|
| 54 |
last_conv_layer_output = last_conv_layer_output[0]
|
| 55 |
heatmap = last_conv_layer_output @ pooled_grads[..., tf.newaxis]
|
|
|
|
| 58 |
return heatmap.numpy()
|
| 59 |
|
| 60 |
def superimpose_gradcam(original_img_pil, heatmap):
|
| 61 |
+
"""Overlays the heatmap on the original image."""
|
| 62 |
original_img = np.array(original_img_pil)
|
| 63 |
heatmap = cv2.resize(heatmap, (original_img.shape[1], original_img.shape[0]))
|
| 64 |
heatmap = np.uint8(255 * heatmap)
|
|
|
|
| 65 |
heatmap = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET)
|
|
|
|
| 66 |
superimposed_img = cv2.addWeighted(original_img, 0.6, heatmap, 0.4, 0)
|
| 67 |
return Image.fromarray(superimposed_img)
|
| 68 |
|