m0hsin123 commited on
Commit
a715d88
ยท
verified ยท
1 Parent(s): 3b16a27

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +42 -72
app.py CHANGED
@@ -3,6 +3,10 @@ import gradio as gr
3
  import timm
4
  from torchvision import transforms as T
5
  from PIL import Image
 
 
 
 
6
 
7
  # ==========================================
8
  # 1. Configuration & Setup
@@ -42,49 +46,45 @@ transform = T.Compose([
42
  ])
43
 
44
  # ==========================================
45
- # 4. Styled Text Blocks & Inference
46
  # ==========================================
47
- # Styled "Waiting" Box - Soft light gray background with dashed border
48
- waiting_text = """
49
- <div style="background-color: #f1f5f9; padding: 15px; border-radius: 10px; border: 2px dashed #cbd5e1; text-align: center; margin-bottom: 15px;">
50
- <h3 style="color: #64748b; margin: 0; font-weight: 600;">โณ Waiting for upload...</h3>
51
- </div>
52
- """
53
 
54
  def predict(image):
55
  if image is None:
56
- return None, waiting_text
57
 
 
58
  image = image.convert("RGB")
59
  input_tensor = transform(image).unsqueeze(0).to(device)
60
 
 
61
  with torch.no_grad():
62
  outputs = model(input_tensor)
63
  probabilities = torch.nn.functional.softmax(outputs[0], dim=0)
64
 
65
- # Format for Gradio Label component
66
- confidences = {class_names[i]: float(
67
- probabilities[i]) for i in range(len(class_names))}
68
-
69
- # Get top prediction for the text output
70
  top_class = max(confidences, key=confidences.get)
71
  top_score = confidences[top_class]
72
 
73
- # Styled Success Box - Soft light indigo background, dark indigo text, nice shadow
74
- message = f"""
75
- <div style="background-color: #e0e7ff; padding: 15px; border-radius: 10px; border-left: 6px solid #4f46e5; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); text-align: center; margin-bottom: 15px;">
76
- <h3 style="color: #312e81; margin: 0; font-weight: 800; font-size: 1.2rem;">
77
- ๐Ÿง  The model is {top_score*100:.1f}% confident that the primary expression is {top_class}.
78
- </h3>
79
- </div>
80
- """
81
 
82
- return confidences, message
 
 
 
 
 
 
 
 
 
 
 
83
 
84
  # ==========================================
85
  # 5. Modern Gradio UI (Blocks)
86
  # ==========================================
87
- # Using a sleek, soft theme
88
  theme = gr.themes.Soft(
89
  primary_hue="indigo",
90
  secondary_hue="blue",
@@ -93,32 +93,14 @@ theme = gr.themes.Soft(
93
  )
94
 
95
  custom_css = """
96
- .gradio-container {
97
- background-color: #f8fafc;
98
- }
99
- .header-box {
100
- text-align: center;
101
- padding: 2rem;
102
- background: linear-gradient(135deg, #4f46e5 0%, #3b82f6 100%);
103
- border-radius: 15px;
104
- color: white;
105
- box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
106
- margin-bottom: 20px;
107
- }
108
- .header-title {
109
- font-size: 2.5rem;
110
- font-weight: 800;
111
- margin-bottom: 0.5rem;
112
- }
113
- .header-subtitle {
114
- font-size: 1.1rem;
115
- opacity: 0.9;
116
- }
117
  """
118
 
119
  with gr.Blocks(theme=theme, css=custom_css) as demo:
120
 
121
- # --- Custom Header ---
122
  gr.HTML("""
123
  <div class="header-box">
124
  <div class="header-title">โœจ Autistic Children Expression Recognition</div>
@@ -126,59 +108,47 @@ with gr.Blocks(theme=theme, css=custom_css) as demo:
126
  </div>
127
  """)
128
 
129
- # --- Main App Layout ---
130
  with gr.Row():
131
-
132
  # Left Column: Inputs
133
  with gr.Column(scale=1):
134
- # Styled Upload Header - White card, subtle shadow, indigo accent
135
- gr.HTML("""
136
- <div style="background-color: #ffffff; padding: 15px; border-radius: 10px; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); border-left: 5px solid #4f46e5; margin-bottom: 15px;">
137
- <h3 style="color: #1e293b; margin: 0 0 5px 0; font-weight: 800;">๐Ÿ“ธ Upload Image</h3>
138
- <p style="color: #475569; margin: 0; font-size: 0.95rem;">Upload a clear photo of a child's face to begin the analysis.</p>
139
- </div>
140
- """)
141
- input_image = gr.Image(
142
- type="pil", label="Input Image", elem_classes="image-box")
143
 
144
  with gr.Row():
145
  clear_btn = gr.Button("๐Ÿ—‘๏ธ Clear", variant="secondary")
146
- submit_btn = gr.Button(
147
- "๐Ÿš€ Analyze Expression", variant="primary")
148
 
149
- # Right Column: Outputs
150
  with gr.Column(scale=1):
151
- # Styled Results Header - White card, subtle shadow, blue accent
152
- gr.HTML("""
153
- <div style="background-color: #ffffff; padding: 15px; border-radius: 10px; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); border-left: 5px solid #3b82f6; margin-bottom: 15px;">
154
- <h3 style="color: #1e293b; margin: 0; font-weight: 800;">๐Ÿ“Š AI Analysis Results</h3>
155
- </div>
156
- """)
157
 
 
158
  output_message = gr.HTML(waiting_text)
159
- output_label = gr.Label(
160
- num_top_classes=4, label="Confidence Scores")
 
 
161
 
162
- # --- Expandable Info Section ---
163
  with gr.Accordion("โ„น๏ธ About this Model", open=False):
164
  gr.Markdown("""
165
  * **Architecture:** ResNeXt-101 (32x8d)
166
  * **Input Resolution:** 224x224 pixels
 
167
  * **Task:** Multi-class Facial Expression Classification
168
  * **Note:** This tool is for educational/research demonstration purposes and is not a clinical diagnostic tool.
169
  """)
170
 
171
- # --- Button Functionality ---
172
  submit_btn.click(
173
  fn=predict,
174
  inputs=[input_image],
175
- outputs=[output_label, output_message]
176
  )
177
 
178
  clear_btn.click(
179
- fn=lambda: (None, None, waiting_text),
180
  inputs=[],
181
- outputs=[input_image, output_label, output_message]
182
  )
183
 
184
  if __name__ == "__main__":
 
3
  import timm
4
  from torchvision import transforms as T
5
  from PIL import Image
6
+ import numpy as np
7
+ import cv2
8
+ from pytorch_grad_cam import GradCAMPlusPlus
9
+ from pytorch_grad_cam.utils.image import show_cam_on_image
10
 
11
  # ==========================================
12
  # 1. Configuration & Setup
 
46
  ])
47
 
48
  # ==========================================
49
+ # 4. Inference & Grad-CAM Function
50
  # ==========================================
51
+ waiting_text = "<div style='background: #f8fafc; color: #475569; padding: 10px; border-radius: 5px;'><h3>Waiting for upload...</h3></div>"
 
 
 
 
 
52
 
53
  def predict(image):
54
  if image is None:
55
+ return None, waiting_text, None
56
 
57
+ # Prepare Image
58
  image = image.convert("RGB")
59
  input_tensor = transform(image).unsqueeze(0).to(device)
60
 
61
+ # 1. Classification (Inside no_grad)
62
  with torch.no_grad():
63
  outputs = model(input_tensor)
64
  probabilities = torch.nn.functional.softmax(outputs[0], dim=0)
65
 
66
+ confidences = {class_names[i]: float(probabilities[i]) for i in range(len(class_names))}
 
 
 
 
67
  top_class = max(confidences, key=confidences.get)
68
  top_score = confidences[top_class]
69
 
70
+ message = f"<div style='background: #e0e7ff; color: #1e3a8a; padding: 10px; border-radius: 5px;'><h3>๐Ÿง  The model is <b>{top_score*100:.1f}%</b> confident that the primary expression is <b>{top_class}</b>.</h3></div>"
 
 
 
 
 
 
 
71
 
72
+ # 2. Grad-CAM Generation (Outside no_grad because Grad-CAM requires gradients)
73
+ target_layers = [model.layer4[-1].conv3]
74
+ cam = GradCAMPlusPlus(model=model, target_layers=target_layers, use_cuda=False) # CPU mode
75
+
76
+ # Generate heatmap
77
+ grayscale_cam = cam(input_tensor=input_tensor)[0, :]
78
+
79
+ # Overlay heatmap on original image
80
+ rgb_img = np.array(image.resize((im_size, im_size))) / 255.0
81
+ cam_image = show_cam_on_image(rgb_img, grayscale_cam, use_rgb=True, image_weight=0.4)
82
+
83
+ return confidences, message, cam_image
84
 
85
  # ==========================================
86
  # 5. Modern Gradio UI (Blocks)
87
  # ==========================================
 
88
  theme = gr.themes.Soft(
89
  primary_hue="indigo",
90
  secondary_hue="blue",
 
93
  )
94
 
95
  custom_css = """
96
+ .gradio-container { background-color: #f8fafc; }
97
+ .header-box { text-align: center; padding: 2rem; background: linear-gradient(135deg, #4f46e5 0%, #3b82f6 100%); border-radius: 15px; color: white; box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1); margin-bottom: 20px; }
98
+ .header-title { font-size: 2.5rem; font-weight: 800; margin-bottom: 0.5rem; }
99
+ .header-subtitle { font-size: 1.1rem; opacity: 0.9; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
  """
101
 
102
  with gr.Blocks(theme=theme, css=custom_css) as demo:
103
 
 
104
  gr.HTML("""
105
  <div class="header-box">
106
  <div class="header-title">โœจ Autistic Children Expression Recognition</div>
 
108
  </div>
109
  """)
110
 
 
111
  with gr.Row():
 
112
  # Left Column: Inputs
113
  with gr.Column(scale=1):
114
+ gr.HTML("<div style='background: #f1f5f9; color: #0f172a; padding: 10px; border-radius: 5px;'><h3>๐Ÿ“ธ Upload Image</h3>Upload a clear photo of a child's face.</div>")
115
+ input_image = gr.Image(type="pil", label="Input Image", elem_classes="image-box")
 
 
 
 
 
 
 
116
 
117
  with gr.Row():
118
  clear_btn = gr.Button("๐Ÿ—‘๏ธ Clear", variant="secondary")
119
+ submit_btn = gr.Button("๐Ÿš€ Analyze Expression", variant="primary")
 
120
 
121
+ # Right Column: Outputs (Parallel to Input)
122
  with gr.Column(scale=1):
123
+ gr.HTML("<div style='background: #f1f5f9; color: #0f172a; padding: 10px; border-radius: 5px;'><h3>๐Ÿ“Š AI Analysis & Grad-CAM</h3></div>")
 
 
 
 
 
124
 
125
+ # Message and Label block
126
  output_message = gr.HTML(waiting_text)
127
+
128
+ with gr.Row():
129
+ output_label = gr.Label(num_top_classes=4, label="Confidence Scores")
130
+ output_cam = gr.Image(type="numpy", label="Grad-CAM Focus Map")
131
 
 
132
  with gr.Accordion("โ„น๏ธ About this Model", open=False):
133
  gr.Markdown("""
134
  * **Architecture:** ResNeXt-101 (32x8d)
135
  * **Input Resolution:** 224x224 pixels
136
+ * **Visualizer:** Grad-CAM++ (Highlights where the AI is looking)
137
  * **Task:** Multi-class Facial Expression Classification
138
  * **Note:** This tool is for educational/research demonstration purposes and is not a clinical diagnostic tool.
139
  """)
140
 
141
+ # Button Functionality
142
  submit_btn.click(
143
  fn=predict,
144
  inputs=[input_image],
145
+ outputs=[output_label, output_message, output_cam]
146
  )
147
 
148
  clear_btn.click(
149
+ fn=lambda: (None, waiting_text, None),
150
  inputs=[],
151
+ outputs=[input_image, output_label, output_message, output_cam]
152
  )
153
 
154
  if __name__ == "__main__":