JKrishnanandhaa commited on
Commit
e89409d
·
verified ·
1 Parent(s): 9e9ab33

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +116 -8
app.py CHANGED
@@ -84,6 +84,82 @@ def create_gauge_chart(value: float, title: str, max_value: float = 1.0) -> go.F
84
  return fig
85
 
86
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  class ForgeryDetector:
88
  """Main forgery detection pipeline"""
89
 
@@ -211,10 +287,38 @@ class ForgeryDetector:
211
  # Create visualization
212
  overlay = self._create_overlay(original_image, results)
213
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
  # Create HTML response
215
  results_html = self._create_html_report(results)
216
 
217
- return overlay, results_html
218
 
219
  def _create_overlay(self, image, results):
220
  """Create overlay visualization"""
@@ -308,15 +412,15 @@ def detect_forgery(file):
308
  try:
309
  if file is None:
310
  empty_html = "<div style='padding:12px; border:1px solid #d9534f; border-radius:8px;'>❌ <b>No file uploaded.</b></div>"
311
- return None, empty_html
312
 
313
  # Get file path
314
  file_path = file if isinstance(file, str) else file
315
 
316
  # Detect forgeries
317
- overlay, results_html = detector.detect(file_path)
318
 
319
- return overlay, results_html
320
 
321
  except Exception as e:
322
  import traceback
@@ -327,7 +431,7 @@ def detect_forgery(file):
327
  ❌ <b>Error:</b> {str(e)}
328
  </div>
329
  """
330
- return None, error_html
331
 
332
 
333
  # Custom CSS - subtle styling
@@ -397,6 +501,10 @@ with gr.Blocks(css=custom_css) as demo:
397
  output_html = gr.HTML(
398
  value="<i>No analysis yet. Upload a document and click Analyze.</i>"
399
  )
 
 
 
 
400
 
401
  gr.Markdown("---")
402
 
@@ -441,13 +549,13 @@ with gr.Blocks(css=custom_css) as demo:
441
  analyze_btn.click(
442
  fn=detect_forgery,
443
  inputs=[input_file],
444
- outputs=[output_image, output_html]
445
  )
446
 
447
  clear_btn.click(
448
- fn=lambda: (None, None, "<i>No analysis yet. Upload a document and click Analyze.</i>"),
449
  inputs=None,
450
- outputs=[input_file, output_image, output_html]
451
  )
452
 
453
 
 
84
  return fig
85
 
86
 
87
+ def create_detection_metrics_gauge(avg_confidence: float, iou: float, precision: float, recall: float, num_detections: int) -> go.Figure:
88
+ """Create concentric radial gauge showing actual detection metrics"""
89
+
90
+ # Calculate percentages for display
91
+ confidence_pct = avg_confidence * 100 if num_detections > 0 else 0
92
+ iou_pct = iou * 100
93
+ precision_pct = precision * 100
94
+ recall_pct = recall * 100
95
+
96
+ fig = go.Figure()
97
+
98
+ # Add concentric gauge rings (from outer to inner)
99
+ fig.add_trace(go.Indicator(
100
+ mode="gauge",
101
+ value=confidence_pct,
102
+ domain={'x': [0, 1], 'y': [0, 1]},
103
+ title={'text': f"Confidence: {confidence_pct:.1f}%", 'font': {'size': 11}},
104
+ gauge={
105
+ 'axis': {'range': [0, 100], 'visible': False},
106
+ 'bar': {'color': '#4169E1', 'thickness': 0.15},
107
+ 'bgcolor': 'rgba(0,0,0,0.05)',
108
+ 'borderwidth': 0,
109
+ }
110
+ ))
111
+
112
+ fig.add_trace(go.Indicator(
113
+ mode="gauge",
114
+ value=precision_pct,
115
+ domain={'x': [0.1, 0.9], 'y': [0.1, 0.9]},
116
+ title={'text': f"Precision: {precision_pct:.1f}%", 'font': {'size': 10}},
117
+ gauge={
118
+ 'axis': {'range': [0, 100], 'visible': False},
119
+ 'bar': {'color': '#5cb85c', 'thickness': 0.15},
120
+ 'bgcolor': 'rgba(0,0,0,0.05)',
121
+ 'borderwidth': 0,
122
+ }
123
+ ))
124
+
125
+ fig.add_trace(go.Indicator(
126
+ mode="gauge",
127
+ value=recall_pct,
128
+ domain={'x': [0.2, 0.8], 'y': [0.2, 0.8]},
129
+ title={'text': f"Recall: {recall_pct:.1f}%", 'font': {'size': 9}},
130
+ gauge={
131
+ 'axis': {'range': [0, 100], 'visible': False},
132
+ 'bar': {'color': '#f0ad4e', 'thickness': 0.15},
133
+ 'bgcolor': 'rgba(0,0,0,0.05)',
134
+ 'borderwidth': 0,
135
+ }
136
+ ))
137
+
138
+ fig.add_trace(go.Indicator(
139
+ mode="gauge+number",
140
+ value=iou_pct,
141
+ domain={'x': [0.3, 0.7], 'y': [0.3, 0.7]},
142
+ title={'text': "IoU", 'font': {'size': 10}},
143
+ number={'suffix': '%', 'font': {'size': 16}},
144
+ gauge={
145
+ 'axis': {'range': [0, 100], 'visible': False},
146
+ 'bar': {'color': '#d9534f', 'thickness': 0.2},
147
+ 'bgcolor': 'rgba(0,0,0,0.05)',
148
+ 'borderwidth': 0,
149
+ }
150
+ ))
151
+
152
+ fig.update_layout(
153
+ paper_bgcolor='rgba(0,0,0,0)',
154
+ plot_bgcolor='rgba(0,0,0,0)',
155
+ height=300,
156
+ margin=dict(l=20, r=20, t=60, b=20),
157
+ showlegend=False
158
+ )
159
+
160
+ return fig
161
+
162
+
163
  class ForgeryDetector:
164
  """Main forgery detection pipeline"""
165
 
 
287
  # Create visualization
288
  overlay = self._create_overlay(original_image, results)
289
 
290
+ # Calculate actual detection metrics from probability map and mask
291
+ num_detections = len(results)
292
+ avg_confidence = sum(r['confidence'] for r in results) / num_detections if num_detections > 0 else 0
293
+
294
+ # Calculate IoU, Precision, Recall from the refined mask and probability map
295
+ if num_detections > 0:
296
+ # Use high-confidence areas from probability map as "predicted positive"
297
+ high_conf_mask = (prob_map > 0.7).astype(np.uint8)
298
+ predicted_positive = np.sum(refined_mask > 0)
299
+ high_conf_positive = np.sum(high_conf_mask > 0)
300
+
301
+ # Calculate intersection and union
302
+ intersection = np.sum((refined_mask > 0) & (high_conf_mask > 0))
303
+ union = np.sum((refined_mask > 0) | (high_conf_mask > 0))
304
+
305
+ # Calculate metrics
306
+ iou = intersection / union if union > 0 else 0
307
+ precision = intersection / predicted_positive if predicted_positive > 0 else 0
308
+ recall = intersection / high_conf_positive if high_conf_positive > 0 else 0
309
+ else:
310
+ # No detections - use zeros
311
+ iou = 0
312
+ precision = 0
313
+ recall = 0
314
+
315
+ # Create detection metrics gauge with actual values
316
+ metrics_gauge = create_detection_metrics_gauge(avg_confidence, iou, precision, recall, num_detections)
317
+
318
  # Create HTML response
319
  results_html = self._create_html_report(results)
320
 
321
+ return overlay, metrics_gauge, results_html
322
 
323
  def _create_overlay(self, image, results):
324
  """Create overlay visualization"""
 
412
  try:
413
  if file is None:
414
  empty_html = "<div style='padding:12px; border:1px solid #d9534f; border-radius:8px;'>❌ <b>No file uploaded.</b></div>"
415
+ return None, None, empty_html
416
 
417
  # Get file path
418
  file_path = file if isinstance(file, str) else file
419
 
420
  # Detect forgeries
421
+ overlay, metrics_gauge, results_html = detector.detect(file_path)
422
 
423
+ return overlay, metrics_gauge, results_html
424
 
425
  except Exception as e:
426
  import traceback
 
431
  ❌ <b>Error:</b> {str(e)}
432
  </div>
433
  """
434
+ return None, None, error_html
435
 
436
 
437
  # Custom CSS - subtle styling
 
501
  output_html = gr.HTML(
502
  value="<i>No analysis yet. Upload a document and click Analyze.</i>"
503
  )
504
+
505
+ with gr.Column(scale=1):
506
+ gr.Markdown("### Detection Metrics")
507
+ metrics_gauge = gr.Plot(label="Concentric Metrics Gauge")
508
 
509
  gr.Markdown("---")
510
 
 
549
  analyze_btn.click(
550
  fn=detect_forgery,
551
  inputs=[input_file],
552
+ outputs=[output_image, metrics_gauge, output_html]
553
  )
554
 
555
  clear_btn.click(
556
+ fn=lambda: (None, None, None, "<i>No analysis yet. Upload a document and click Analyze.</i>"),
557
  inputs=None,
558
+ outputs=[input_file, output_image, metrics_gauge, output_html]
559
  )
560
 
561