luigi12345 commited on
Commit
4234218
1 Parent(s): f192f0b
Files changed (1) hide show
  1. app.py +120 -58
app.py CHANGED
@@ -8,6 +8,10 @@ import streamlit as st
8
  from PIL import Image
9
  import io
10
  import zipfile
 
 
 
 
11
 
12
  # --- GlaucomaModel Class ---
13
  class GlaucomaModel(object):
@@ -108,6 +112,73 @@ def get_confidence_level(confidence):
108
  else:
109
  return "Very Low"
110
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
  # --- Streamlit Interface ---
112
  def main():
113
  st.set_page_config(layout="wide", page_title="Glaucoma Screening Tool")
@@ -132,63 +203,54 @@ def main():
132
  help="Images with confidence above this threshold will be marked as reliable predictions")
133
 
134
  if uploaded_files:
135
- for uploaded_file in uploaded_files:
136
- image = Image.open(uploaded_file).convert('RGB')
137
- image_np = np.array(image).astype(np.uint8)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
138
 
139
- st.markdown(f"## 📊 Analysis Results: {uploaded_file.name}")
 
 
 
 
 
 
140
 
141
- with st.spinner(f'🔄 Processing {uploaded_file.name}...'):
142
- model = GlaucomaModel(device=torch.device("cuda:0" if torch.cuda.is_available() else "cpu"))
143
- disease_idx, disc_cup_image, vcdr, cls_conf, cup_conf, disc_conf, cropped_image = model.process(image_np)
144
-
145
- # Image display section
146
- st.subheader("Original Image")
147
- st.image(image_np, use_column_width=True)
148
- st.subheader("Segmentation Overlay")
149
- st.image(disc_cup_image, use_column_width=True)
150
- st.subheader("Region of Interest")
151
- st.image(cropped_image, use_column_width=True)
152
-
153
- st.markdown("---")
154
-
155
- # Classification Results
156
- st.markdown("### 🔍 Classification")
157
- diagnosis = model.cls_id2label[disease_idx]
158
- is_confident = cls_conf >= confidence_threshold
159
-
160
- if diagnosis == "Glaucoma":
161
- st.markdown(f"<div style='padding: 10px; background-color: #ffebee; border-radius: 5px;'>"
162
- f"<h4 style='color: #c62828;'>Diagnosis: {diagnosis}</h4></div>",
163
- unsafe_allow_html=True)
164
- else:
165
- st.markdown(f"<div style='padding: 10px; background-color: #e8f5e9; border-radius: 5px;'>"
166
- f"<h4 style='color: #2e7d32;'>Diagnosis: {diagnosis}</h4></div>",
167
- unsafe_allow_html=True)
168
-
169
- st.write(f"Classification Confidence: {cls_conf:.1f}%")
170
- if not is_confident:
171
- st.warning("⚠️ Below confidence threshold")
172
-
173
- # Segmentation Results
174
- st.markdown("### 🎯 Segmentation Quality")
175
- st.write(f"Optic Cup Confidence: {cup_conf:.1f}%")
176
- st.write(f"Optic Disc Confidence: {disc_conf:.1f}%")
177
-
178
- cup_level = get_confidence_level(cup_conf)
179
- disc_level = get_confidence_level(disc_conf)
180
- st.info(f"Cup Detection: {cup_level}\nDisc Detection: {disc_level}")
181
-
182
- # Clinical Metrics
183
- st.markdown("### 📏 Clinical Metrics")
184
- st.write(f"Cup-to-Disc Ratio (CDR): {vcdr:.3f}")
185
-
186
- if vcdr > 0.7:
187
- st.warning("⚠️ Elevated CDR (>0.7)")
188
- elif vcdr > 0.5:
189
- st.info("ℹ️ Borderline CDR (0.5-0.7)")
190
- else:
191
- st.success("✅ Normal CDR (<0.5)")
192
-
193
- st.markdown("---")
194
- # ... rest of the code remains the same ...
 
8
  from PIL import Image
9
  import io
10
  import zipfile
11
+ import pandas as pd
12
+ from datetime import datetime
13
+ import os
14
+ import tempfile
15
 
16
  # --- GlaucomaModel Class ---
17
  class GlaucomaModel(object):
 
112
  else:
113
  return "Very Low"
114
 
115
+ def process_batch(model, images_data, progress_bar=None):
116
+ results = []
117
+ for idx, (file_name, image) in enumerate(images_data):
118
+ try:
119
+ disease_idx, disc_cup_image, vcdr, cls_conf, cup_conf, disc_conf, cropped_image = model.process(image)
120
+ results.append({
121
+ 'file_name': file_name,
122
+ 'diagnosis': model.cls_id2label[disease_idx],
123
+ 'confidence': cls_conf,
124
+ 'vcdr': vcdr,
125
+ 'cup_conf': cup_conf,
126
+ 'disc_conf': disc_conf,
127
+ 'processed_image': disc_cup_image,
128
+ 'cropped_image': cropped_image
129
+ })
130
+ if progress_bar:
131
+ progress_bar.progress((idx + 1) / len(images_data))
132
+ except Exception as e:
133
+ st.error(f"Error processing {file_name}: {str(e)}")
134
+ return results
135
+
136
+ def save_results(results, original_images):
137
+ # Create temporary directory for results
138
+ with tempfile.TemporaryDirectory() as temp_dir:
139
+ # Save report as CSV
140
+ df = pd.DataFrame([{
141
+ 'File': r['file_name'],
142
+ 'Diagnosis': r['diagnosis'],
143
+ 'Confidence (%)': f"{r['confidence']:.1f}",
144
+ 'VCDR': f"{r['vcdr']:.3f}",
145
+ 'Cup Confidence (%)': f"{r['cup_conf']:.1f}",
146
+ 'Disc Confidence (%)': f"{r['disc_conf']:.1f}"
147
+ } for r in results])
148
+
149
+ report_path = os.path.join(temp_dir, 'report.csv')
150
+ df.to_csv(report_path, index=False)
151
+
152
+ # Save processed images
153
+ for result, orig_img in zip(results, original_images):
154
+ img_name = result['file_name']
155
+ base_name = os.path.splitext(img_name)[0]
156
+
157
+ # Save original
158
+ orig_path = os.path.join(temp_dir, f"{base_name}_original.jpg")
159
+ Image.fromarray(orig_img).save(orig_path)
160
+
161
+ # Save segmentation
162
+ seg_path = os.path.join(temp_dir, f"{base_name}_segmentation.jpg")
163
+ Image.fromarray(result['processed_image']).save(seg_path)
164
+
165
+ # Save ROI
166
+ roi_path = os.path.join(temp_dir, f"{base_name}_roi.jpg")
167
+ Image.fromarray(result['cropped_image']).save(roi_path)
168
+
169
+ # Create ZIP file
170
+ zip_path = os.path.join(temp_dir, 'results.zip')
171
+ with zipfile.ZipFile(zip_path, 'w') as zipf:
172
+ for root, _, files in os.walk(temp_dir):
173
+ for file in files:
174
+ if file != 'results.zip':
175
+ file_path = os.path.join(root, file)
176
+ arcname = os.path.basename(file_path)
177
+ zipf.write(file_path, arcname)
178
+
179
+ with open(zip_path, 'rb') as f:
180
+ return f.read()
181
+
182
  # --- Streamlit Interface ---
183
  def main():
184
  st.set_page_config(layout="wide", page_title="Glaucoma Screening Tool")
 
203
  help="Images with confidence above this threshold will be marked as reliable predictions")
204
 
205
  if uploaded_files:
206
+ st.markdown("## 📊 Batch Analysis Results")
207
+
208
+ # Initialize model once for all images
209
+ model = GlaucomaModel(device=torch.device("cuda:0" if torch.cuda.is_available() else "cpu"))
210
+
211
+ # Prepare images data
212
+ images_data = []
213
+ original_images = []
214
+ for file in uploaded_files:
215
+ try:
216
+ image = Image.open(file).convert('RGB')
217
+ image_np = np.array(image)
218
+ images_data.append((file.name, image_np))
219
+ original_images.append(image_np)
220
+ except Exception as e:
221
+ st.error(f"Error loading {file.name}: {str(e)}")
222
+ continue
223
+
224
+ progress_bar = st.progress(0)
225
+ st.write(f"Processing {len(images_data)} images...")
226
+
227
+ # Process all images
228
+ results = process_batch(model, images_data, progress_bar)
229
+
230
+ if results:
231
+ # Generate ZIP with results
232
+ zip_data = save_results(results, original_images)
233
 
234
+ # Download button for ZIP
235
+ st.download_button(
236
+ label="📥 Download All Results",
237
+ data=zip_data,
238
+ file_name=f"glaucoma_screening_{datetime.now().strftime('%Y%m%d_%H%M%S')}.zip",
239
+ mime="application/zip"
240
+ )
241
 
242
+ # Display results
243
+ for result in results:
244
+ with st.expander(f"Results for {result['file_name']}"):
245
+ cols = st.columns(3)
246
+ with cols[0]:
247
+ st.image(result['processed_image'], caption="Segmentation", use_column_width=True)
248
+ with cols[1]:
249
+ st.image(result['cropped_image'], caption="ROI", use_column_width=True)
250
+ with cols[2]:
251
+ st.write("### Metrics")
252
+ st.write(f"Diagnosis: {result['diagnosis']}")
253
+ st.write(f"Confidence: {result['confidence']:.1f}%")
254
+ st.write(f"VCDR: {result['vcdr']:.3f}")
255
+ st.write(f"Cup Confidence: {result['cup_conf']:.1f}%")
256
+ st.write(f"Disc Confidence: {result['disc_conf']:.1f}%")