JobenTan commited on
Commit
228fdbb
·
verified ·
1 Parent(s): 5c6b7fc

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +61 -18
app.py CHANGED
@@ -9,6 +9,8 @@ from albumentations.pytorch import ToTensorV2
9
  from torchvision import transforms
10
  import segmentation_models_pytorch as smp
11
  import torch.nn as nn
 
 
12
 
13
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
14
 
@@ -41,13 +43,52 @@ classifier_transform = transforms.Compose([
41
  transforms.Normalize(mean=0.41, std=0.16)
42
  ])
43
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  # Inference Function
45
  def analyze(image):
46
- # Convert to grayscale for UNet
47
  image_gray = image.convert("L")
48
  img_np = np.array(image_gray)
49
 
50
- # Preprocess for UNet
51
  augmented = unet_transform(image=img_np)
52
  unet_input = augmented["image"].unsqueeze(0).to(device)
53
 
@@ -56,37 +97,39 @@ def analyze(image):
56
  mask_pred = torch.sigmoid(mask_pred)
57
  mask_binary = (mask_pred > 0.5).float()
58
 
59
- # Resize original image and mask to 224x224 for classifier
60
  resized = image_gray.resize((224, 224), Image.BILINEAR)
61
  mask_resized = transforms.functional.resize(mask_binary, [224, 224])
62
-
63
- image_np = np.array(resized).astype(np.float32) # shape: (224, 224)
64
- mask_np = (mask_resized.squeeze().cpu().numpy() > 0.5).astype(np.float32) # shape: (224, 224)
65
 
66
- # Apply mask and convert to 3-channel image
 
 
67
  lung_image = image_np * mask_np
68
- lung_image_3ch = np.stack([lung_image] * 3, axis=-1) # shape: (224, 224, 3)
69
  lung_image_3ch = np.clip(lung_image_3ch, 0, 255).astype(np.uint8)
70
  lung_image_pil = Image.fromarray(lung_image_3ch)
71
 
72
- # Classification
73
  input_tensor = classifier_transform(lung_image_pil).unsqueeze(0).to(device)
74
 
75
- with torch.no_grad():
76
- logits = m2(input_tensor)
77
- probs = torch.softmax(logits, dim=1)
78
- confidence, pred_class = torch.max(probs, dim=1)
 
 
 
79
 
80
  classes = ["COVID", "Lung_Opacity", "Normal", "Viral Pneumonia"]
81
- return f"Prediction: {classes[pred_class.item()]} ({confidence.item()*100:.2f}%)"
 
 
82
 
83
  # Gradio UI
84
  interface = gr.Interface(
85
  fn=analyze,
86
  inputs=gr.Image(type="pil"),
87
- outputs="text",
88
- title="Chest X-Ray Analysis",
89
- description="Upload a chest X-ray to detect disease based on segmentation and classification models."
90
  )
91
 
92
- interface.launch()
 
9
  from torchvision import transforms
10
  import segmentation_models_pytorch as smp
11
  import torch.nn as nn
12
+ import cv2
13
+ import matplotlib.cm as cm
14
 
15
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
16
 
 
43
  transforms.Normalize(mean=0.41, std=0.16)
44
  ])
45
 
46
+ # Grad-CAM function
47
+ def generate_gradcam(model, image_tensor, target_class):
48
+ gradients = []
49
+ activations = []
50
+
51
+ def backward_hook(module, grad_input, grad_output):
52
+ gradients.append(grad_output[0])
53
+
54
+ def forward_hook(module, input, output):
55
+ activations.append(output)
56
+
57
+ final_conv = model.features[-1]
58
+ handle_fwd = final_conv.register_forward_hook(forward_hook)
59
+ handle_bwd = final_conv.register_backward_hook(backward_hook)
60
+
61
+ model.zero_grad()
62
+ output = model(image_tensor)
63
+ class_score = output[0, target_class]
64
+ class_score.backward()
65
+
66
+ grads_val = gradients[0].cpu().numpy()[0]
67
+ activations_val = activations[0].cpu().numpy()[0]
68
+
69
+ weights = np.mean(grads_val, axis=(1, 2))
70
+ cam = np.zeros(activations_val.shape[1:], dtype=np.float32)
71
+ for i, w in enumerate(weights):
72
+ cam += w * activations_val[i]
73
+
74
+ cam = np.maximum(cam, 0)
75
+ cam = cv2.resize(cam, (224, 224))
76
+ cam = cam - np.min(cam)
77
+ cam = cam / np.max(cam + 1e-8)
78
+
79
+ heatmap = cm.jet(cam)[:, :, :3] # RGB heatmap
80
+ heatmap = (heatmap * 255).astype(np.uint8)
81
+
82
+ handle_fwd.remove()
83
+ handle_bwd.remove()
84
+
85
+ return heatmap
86
+
87
  # Inference Function
88
  def analyze(image):
 
89
  image_gray = image.convert("L")
90
  img_np = np.array(image_gray)
91
 
 
92
  augmented = unet_transform(image=img_np)
93
  unet_input = augmented["image"].unsqueeze(0).to(device)
94
 
 
97
  mask_pred = torch.sigmoid(mask_pred)
98
  mask_binary = (mask_pred > 0.5).float()
99
 
 
100
  resized = image_gray.resize((224, 224), Image.BILINEAR)
101
  mask_resized = transforms.functional.resize(mask_binary, [224, 224])
 
 
 
102
 
103
+ image_np = np.array(resized).astype(np.float32)
104
+ mask_np = (mask_resized.squeeze().cpu().numpy() > 0.5).astype(np.float32)
105
+
106
  lung_image = image_np * mask_np
107
+ lung_image_3ch = np.stack([lung_image] * 3, axis=-1)
108
  lung_image_3ch = np.clip(lung_image_3ch, 0, 255).astype(np.uint8)
109
  lung_image_pil = Image.fromarray(lung_image_3ch)
110
 
 
111
  input_tensor = classifier_transform(lung_image_pil).unsqueeze(0).to(device)
112
 
113
+ logits = m2(input_tensor)
114
+ probs = torch.softmax(logits, dim=1)
115
+ confidence, pred_class = torch.max(probs, dim=1)
116
+
117
+ heatmap = generate_gradcam(m2, input_tensor, pred_class.item())
118
+ overlay = cv2.addWeighted(lung_image_3ch, 0.5, heatmap, 0.5, 0)
119
+ overlay_pil = Image.fromarray(overlay)
120
 
121
  classes = ["COVID", "Lung_Opacity", "Normal", "Viral Pneumonia"]
122
+ result_text = f"Prediction: {classes[pred_class.item()]} ({confidence.item()*100:.2f}%)"
123
+
124
+ return result_text, overlay_pil
125
 
126
  # Gradio UI
127
  interface = gr.Interface(
128
  fn=analyze,
129
  inputs=gr.Image(type="pil"),
130
+ outputs=[gr.Text(), gr.Image(type="pil")],
131
+ title="Chest X-Ray Analysis with Grad-CAM",
132
+ description="Upload a chest X-ray to detect disease and view model attention using Grad-CAM."
133
  )
134
 
135
+ interface.launch()