AI-Manith commited on
Commit
b8973e6
·
verified ·
1 Parent(s): cd30af5

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +563 -25
src/streamlit_app.py CHANGED
@@ -13,28 +13,566 @@ forums](https://discuss.streamlit.io).
13
  In the meantime, below is an example of what you can do with just a few lines of code:
14
  """
15
 
16
- num_points = st.slider("Number of points in spiral", 1, 10000, 1100)
17
- num_turns = st.slider("Number of turns in spiral", 1, 300, 31)
18
-
19
- indices = np.linspace(0, 1, num_points)
20
- theta = 2 * np.pi * num_turns * indices
21
- radius = indices
22
-
23
- x = radius * np.cos(theta)
24
- y = radius * np.sin(theta)
25
-
26
- df = pd.DataFrame({
27
- "x": x,
28
- "y": y,
29
- "idx": indices,
30
- "rand": np.random.randn(num_points),
31
- })
32
-
33
- st.altair_chart(alt.Chart(df, height=700, width=700)
34
- .mark_point(filled=True)
35
- .encode(
36
- x=alt.X("x", axis=None),
37
- y=alt.Y("y", axis=None),
38
- color=alt.Color("idx", legend=None, scale=alt.Scale()),
39
- size=alt.Size("rand", legend=None, scale=alt.Scale(range=[1, 150])),
40
- ))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  In the meantime, below is an example of what you can do with just a few lines of code:
14
  """
15
 
16
+ """
17
+ Streamlit Web Application for Mango Disease Detection
18
+ Supports image upload, batch processing, and real-time webcam detection
19
+ """
20
+
21
+ import streamlit as st
22
+ import os
23
+ import sys
24
+ import tempfile
25
+ import zipfile
26
+ import shutil
27
+ from datetime import datetime
28
+ import cv2
29
+ import numpy as np
30
+ import time
31
+ import threading
32
+ from queue import Queue
33
+ import base64
34
+ from PIL import Image
35
+ import io
36
+
37
+ # Import the semantic detection system (assuming it's available)
38
+ try:
39
+ from semantic_disease_analyzer import SemanticDiseaseAnalyzer
40
+ ANALYZER_AVAILABLE = True
41
+ except ImportError:
42
+ ANALYZER_AVAILABLE = False
43
+ st.error("semantic_disease_analyzer module not found. Please ensure it's in your Python path.")
44
+
45
+ # Configure Streamlit page
46
+ st.set_page_config(
47
+ page_title="Mango Disease Detection",
48
+ page_icon="🥭",
49
+ layout="wide",
50
+ initial_sidebar_state="expanded"
51
+ )
52
+
53
+ class StreamlitMangoDetector:
54
+ """Streamlit interface for mango disease detection"""
55
+
56
+ def __init__(self):
57
+ if ANALYZER_AVAILABLE:
58
+ if 'analyzer' not in st.session_state:
59
+ with st.spinner("Initializing semantic disease detection system..."):
60
+ try:
61
+ st.session_state.analyzer = SemanticDiseaseAnalyzer()
62
+ st.success("System ready for inference!")
63
+ except Exception as e:
64
+ st.error(f"Error initializing system: {e}")
65
+ st.session_state.analyzer = None
66
+ self.analyzer = st.session_state.analyzer
67
+ else:
68
+ self.analyzer = None
69
+
70
+ def detect_diseases_image(self, image_array, filename="uploaded_image"):
71
+ """Run disease detection on an image array"""
72
+ if not self.analyzer:
73
+ return None
74
+
75
+ try:
76
+ # Create temporary file path without keeping it open
77
+ temp_dir = tempfile.gettempdir()
78
+ temp_filename = f"temp_mango_{int(time.time() * 1000000)}.jpg"
79
+ temp_path = os.path.join(temp_dir, temp_filename)
80
+
81
+ # Convert to PIL Image
82
+ if len(image_array.shape) == 3:
83
+ image = Image.fromarray(image_array)
84
+ else:
85
+ image = Image.fromarray(image_array, mode='L')
86
+
87
+ # Handle different image modes for JPEG conversion
88
+ if image.mode in ('RGBA', 'LA', 'P'):
89
+ # Convert RGBA/LA/P to RGB by creating white background
90
+ if image.mode == 'P':
91
+ image = image.convert('RGBA')
92
+
93
+ # Create white background
94
+ background = Image.new('RGB', image.size, (255, 255, 255))
95
+ if image.mode == 'RGBA':
96
+ background.paste(image, mask=image.split()[-1]) # Use alpha channel as mask
97
+ else: # LA mode
98
+ background.paste(image, mask=image.split()[-1])
99
+ image = background
100
+ elif image.mode not in ('RGB', 'L'):
101
+ # Convert other modes to RGB
102
+ image = image.convert('RGB')
103
+
104
+ # Save image to temporary path
105
+ image.save(temp_path, 'JPEG', quality=95)
106
+
107
+ # Explicitly close the image to release file handles
108
+ image.close()
109
+
110
+ # Run detection
111
+ results = self.analyzer.analyze_image_semantically(
112
+ temp_path, save_results=False
113
+ )
114
+
115
+ # Clean up - try multiple times if needed (Windows file locking issue)
116
+ max_attempts = 3
117
+ for attempt in range(max_attempts):
118
+ try:
119
+ if os.path.exists(temp_path):
120
+ os.remove(temp_path)
121
+ break
122
+ except (PermissionError, OSError) as e:
123
+ if attempt == max_attempts - 1:
124
+ st.warning(f"Could not delete temporary file: {temp_path}")
125
+ else:
126
+ time.sleep(0.1) # Brief pause before retry
127
+
128
+ return results
129
+
130
+ except Exception as e:
131
+ # Cleanup on error
132
+ try:
133
+ if 'temp_path' in locals() and os.path.exists(temp_path):
134
+ os.remove(temp_path)
135
+ except:
136
+ pass
137
+ st.error(f"Detection error: {e}")
138
+ return None
139
+
140
+ def format_results_for_display(self, results):
141
+ """Format detection results for Streamlit display"""
142
+ if not results:
143
+ return "No results available"
144
+
145
+ # Basic detection info
146
+ disease_level = results.get('disease_level', 'Unknown')
147
+ severity = results.get('severity_percentage', 0)
148
+ num_regions = results.get('num_diseased_regions', 0)
149
+
150
+ # Status indicators
151
+ status_colors = {
152
+ 'Healthy': 'green',
153
+ 'Early Disease': 'orange',
154
+ 'Moderate Disease': 'red',
155
+ 'Severe Disease': 'red',
156
+ 'Critical Disease': 'darkred'
157
+ }
158
+
159
+ status_color = status_colors.get(disease_level, 'gray')
160
+
161
+ # Create formatted output
162
+ output = f"""
163
+ ### Detection Results
164
+
165
+ **Status:** <span style="color: {status_color}; font-weight: bold;">{disease_level}</span>
166
+
167
+ **Severity:** {severity:.2f}%
168
+
169
+ **Diseased Regions:** {num_regions}
170
+ """
171
+
172
+ # Add semantic analysis if available
173
+ semantic_info = results.get('semantic_info', {})
174
+ if semantic_info:
175
+ diseases = semantic_info.get('diseases', [])
176
+ if diseases:
177
+ output += "\n**Detected Diseases:**\n"
178
+ for disease in diseases:
179
+ output += f"- {disease['label']}\n"
180
+
181
+ # Economic impact
182
+ economic_impact = semantic_info.get('economic_impact')
183
+ if economic_impact:
184
+ marketability = economic_impact.get('marketability_score', 0)
185
+ output += f"\n**Marketability Score:** {marketability:.0f}%"
186
+
187
+ # Treatment recommendations
188
+ inferences = results.get('ontology_inferences', [])
189
+ treatments = [inf for inf in inferences if any(word in inf.lower()
190
+ for word in ['apply', 'improve', 'remove', 'use', 'avoid', 'reduce'])]
191
+
192
+ if treatments:
193
+ output += "\n\n**Treatment Recommendations:**\n"
194
+ for treatment in treatments[:3]: # Show top 3
195
+ output += f"- {treatment}\n"
196
+
197
+ # Quality assessment
198
+ if severity < 2:
199
+ quality = "Premium Quality"
200
+ recommendation = "Suitable for premium market sale"
201
+ elif severity < 8:
202
+ quality = "Good Quality"
203
+ recommendation = "Monitor for disease progression"
204
+ elif severity < 20:
205
+ quality = "Fair Quality"
206
+ recommendation = "Consider treatment or reduced price sale"
207
+ elif severity < 40:
208
+ quality = "Poor Quality"
209
+ recommendation = "Not suitable for fresh market, consider processing"
210
+ else:
211
+ quality = "Reject"
212
+ recommendation = "Discard to prevent contamination"
213
+
214
+ output += f"\n**Quality Grade:** {quality}\n"
215
+ output += f"**Recommendation:** {recommendation}"
216
+
217
+ return output
218
+
219
+ def main():
220
+ """Main Streamlit application"""
221
+
222
+ # Header
223
+ st.title("Mango Disease Detection System")
224
+ st.markdown("### AI-Powered Semantic Disease Analysis")
225
+
226
+ if not ANALYZER_AVAILABLE:
227
+ st.error("Cannot proceed without the semantic_disease_analyzer module.")
228
+ st.stop()
229
+
230
+ # Initialize detector
231
+ detector = StreamlitMangoDetector()
232
+
233
+ if not detector.analyzer:
234
+ st.error("Failed to initialize the detection system.")
235
+ st.stop()
236
+
237
+ # Sidebar for mode selection
238
+ st.sidebar.title("Detection Mode")
239
+ mode = st.sidebar.selectbox(
240
+ "Choose detection mode:",
241
+ ["Single Image", "Batch Processing", "Webcam Detection", "About"]
242
+ )
243
+
244
+ if mode == "Single Image":
245
+ single_image_mode(detector)
246
+ elif mode == "Batch Processing":
247
+ batch_processing_mode(detector)
248
+ elif mode == "Webcam Detection":
249
+ webcam_mode(detector)
250
+ elif mode == "About":
251
+ about_page()
252
+
253
+ def single_image_mode(detector):
254
+ """Single image upload and detection"""
255
+ st.header("Single Image Detection")
256
+
257
+ col1, col2 = st.columns([1, 1])
258
+
259
+ with col1:
260
+ st.subheader("Upload Image")
261
+ uploaded_file = st.file_uploader(
262
+ "Choose a mango image...",
263
+ type=['jpg', 'jpeg', 'png', 'bmp', 'tiff', 'webp'],
264
+ help="Upload an image of a mango for disease detection"
265
+ )
266
+
267
+ if uploaded_file is not None:
268
+ # Display uploaded image
269
+ image = Image.open(uploaded_file)
270
+ st.image(image, caption="Uploaded Image", use_column_width=True)
271
+
272
+ # Convert to array
273
+ image_array = np.array(image)
274
+
275
+ # Detection button
276
+ if st.button("Analyze Disease", type="primary"):
277
+ with st.spinner("Analyzing image..."):
278
+ results = detector.detect_diseases_image(image_array, uploaded_file.name)
279
+
280
+ if results:
281
+ # Store results in session state
282
+ st.session_state.current_results = results
283
+ st.success("Analysis complete!")
284
+ else:
285
+ st.error("Analysis failed!")
286
+
287
+ with col2:
288
+ st.subheader("Detection Results")
289
+
290
+ if 'current_results' in st.session_state and st.session_state.current_results:
291
+ results = st.session_state.current_results
292
+
293
+ # Display processed image if available
294
+ if 'output_image' in results:
295
+ output_image = results['output_image']
296
+ st.image(output_image, caption="Detection Results", use_column_width=True)
297
+
298
+ # Download button for processed image
299
+ is_success, im_buf_arr = cv2.imencode(".jpg", output_image)
300
+ if is_success:
301
+ byte_im = im_buf_arr.tobytes()
302
+ st.download_button(
303
+ label="Download Result",
304
+ data=byte_im,
305
+ file_name=f"detection_result_{datetime.now().strftime('%Y%m%d_%H%M%S')}.jpg",
306
+ mime="image/jpeg"
307
+ )
308
+
309
+ # Display formatted results
310
+ formatted_results = detector.format_results_for_display(results)
311
+ st.markdown(formatted_results, unsafe_allow_html=True)
312
+
313
+ # Raw results expander
314
+ with st.expander("View Raw Results"):
315
+ st.json(results)
316
+ else:
317
+ st.info("Upload an image and click 'Analyze Disease' to see results here.")
318
+
319
+ def batch_processing_mode(detector):
320
+ """Batch processing for multiple images"""
321
+ st.header("Batch Processing")
322
+
323
+ st.info("Upload multiple images in a ZIP file for batch processing.")
324
+
325
+ uploaded_zip = st.file_uploader(
326
+ "Upload ZIP file containing images:",
327
+ type=['zip'],
328
+ help="ZIP file should contain .jpg, .jpeg, .png, .bmp, .tiff, or .webp images"
329
+ )
330
+
331
+ if uploaded_zip is not None:
332
+ if st.button("Process Batch", type="primary"):
333
+ process_batch(detector, uploaded_zip)
334
+
335
+ def process_batch(detector, uploaded_zip):
336
+ """Process batch of images from ZIP file"""
337
+ try:
338
+ # Create temporary directory
339
+ with tempfile.TemporaryDirectory() as temp_dir:
340
+ # Extract ZIP file
341
+ zip_path = os.path.join(temp_dir, "upload.zip")
342
+ with open(zip_path, "wb") as f:
343
+ f.write(uploaded_zip.getbuffer())
344
+
345
+ with zipfile.ZipFile(zip_path, 'r') as zip_ref:
346
+ zip_ref.extractall(temp_dir)
347
+
348
+ # Find image files
349
+ image_extensions = ['.jpg', '.jpeg', '.png', '.bmp', '.tiff', '.webp']
350
+ image_files = []
351
+
352
+ for root, dirs, files in os.walk(temp_dir):
353
+ for file in files:
354
+ if any(file.lower().endswith(ext) for ext in image_extensions):
355
+ image_files.append(os.path.join(root, file))
356
+
357
+ if not image_files:
358
+ st.error("No valid image files found in the ZIP archive.")
359
+ return
360
+
361
+ st.info(f"Found {len(image_files)} images to process.")
362
+
363
+ # Process images
364
+ results_list = []
365
+ progress_bar = st.progress(0)
366
+ status_text = st.empty()
367
+
368
+ for i, image_path in enumerate(image_files):
369
+ status_text.text(f"Processing {os.path.basename(image_path)}...")
370
+
371
+ try:
372
+ # Load and process image with proper file handling
373
+ with Image.open(image_path) as img:
374
+ # Convert image to array
375
+ image_array = np.array(img)
376
+
377
+ results = detector.detect_diseases_image(image_array, os.path.basename(image_path))
378
+
379
+ if results:
380
+ results['filename'] = os.path.basename(image_path)
381
+ results_list.append(results)
382
+ else:
383
+ st.warning(f"Failed to process: {os.path.basename(image_path)}")
384
+
385
+ except Exception as e:
386
+ st.warning(f"Error processing {os.path.basename(image_path)}: {str(e)}")
387
+
388
+ progress_bar.progress((i + 1) / len(image_files))
389
+
390
+ status_text.text("Batch processing complete!")
391
+
392
+ # Display results summary
393
+ display_batch_results(results_list)
394
+
395
+ except Exception as e:
396
+ st.error(f"Error processing batch: {e}")
397
+
398
+ def display_batch_results(results_list):
399
+ """Display batch processing results"""
400
+ st.subheader("Batch Results Summary")
401
+
402
+ if not results_list:
403
+ st.warning("No successful detections in batch.")
404
+ return
405
+
406
+ # Create summary statistics
407
+ healthy_count = sum(1 for r in results_list if r.get('disease_level') == 'Healthy')
408
+ diseased_count = len(results_list) - healthy_count
409
+ avg_severity = np.mean([r.get('severity_percentage', 0) for r in results_list])
410
+
411
+ col1, col2, col3, col4 = st.columns(4)
412
+
413
+ with col1:
414
+ st.metric("Total Images", len(results_list))
415
+
416
+ with col2:
417
+ st.metric("Healthy", healthy_count, delta=f"{healthy_count/len(results_list)*100:.1f}%")
418
+
419
+ with col3:
420
+ st.metric("Diseased", diseased_count, delta=f"{diseased_count/len(results_list)*100:.1f}%")
421
+
422
+ with col4:
423
+ st.metric("Avg Severity", f"{avg_severity:.1f}%")
424
+
425
+ # Detailed results table
426
+ st.subheader("Detailed Results")
427
+
428
+ # Create results dataframe
429
+ table_data = []
430
+ for result in results_list:
431
+ table_data.append({
432
+ 'Filename': result.get('filename', 'Unknown'),
433
+ 'Status': result.get('disease_level', 'Unknown'),
434
+ 'Severity (%)': f"{result.get('severity_percentage', 0):.1f}",
435
+ 'Diseased Regions': result.get('num_diseased_regions', 0),
436
+ 'Quality': get_quality_grade(result.get('severity_percentage', 0))
437
+ })
438
+
439
+ st.dataframe(table_data, use_container_width=True)
440
+
441
+ # Download results as CSV
442
+ if st.button("Download Results CSV"):
443
+ import pandas as pd
444
+ df = pd.DataFrame(table_data)
445
+ csv = df.to_csv(index=False)
446
+ st.download_button(
447
+ label="Download CSV",
448
+ data=csv,
449
+ file_name=f"batch_results_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv",
450
+ mime="text/csv"
451
+ )
452
+
453
+ def get_quality_grade(severity):
454
+ """Get quality grade based on severity"""
455
+ if severity < 2:
456
+ return "Premium"
457
+ elif severity < 8:
458
+ return "Good"
459
+ elif severity < 20:
460
+ return "Fair"
461
+ elif severity < 40:
462
+ return "Poor"
463
+ else:
464
+ return "Reject"
465
+
466
+ def webcam_mode(detector):
467
+ """Real-time webcam detection"""
468
+ st.header("Real-time Webcam Detection")
469
+
470
+ st.warning("Webcam detection requires additional setup and may not work in all deployment environments.")
471
+
472
+ col1, col2 = st.columns([1, 1])
473
+
474
+ with col1:
475
+ st.subheader("Camera Controls")
476
+
477
+ if st.button("Start Webcam"):
478
+ st.info("Webcam functionality would require additional WebRTC setup for Streamlit deployment.")
479
+ st.code("""
480
+ # For local development, you could use:
481
+ import cv2
482
+
483
+ cap = cv2.VideoCapture(0)
484
+
485
+ # This would need proper WebRTC integration
486
+ # for Streamlit deployment
487
+ """)
488
+
489
+ # Camera settings
490
+ st.selectbox("Camera Quality", ["High (720p)", "Medium (480p)", "Low (360p)"])
491
+ st.slider("Detection Frequency", 1, 30, 5, help="Analyze every Nth frame")
492
+
493
+ with col2:
494
+ st.subheader("Live Detection")
495
+ st.info("Live webcam feed would appear here with real-time disease detection overlay.")
496
+
497
+ # Placeholder for webcam feed
498
+ st.image("https://via.placeholder.com/640x480/cccccc/666666?text=Webcam+Feed+Placeholder",
499
+ caption="Live Camera Feed")
500
+
501
+ def about_page():
502
+ """About page with system information"""
503
+ st.header("About Mango Disease Detection System")
504
+
505
+ st.markdown("""
506
+ ### System Overview
507
+
508
+ This AI-powered system uses computer vision and semantic analysis to detect diseases in mango fruits.
509
+ The system combines:
510
+
511
+ - **Computer Vision**: Deep learning models for image analysis
512
+ - **Semantic Reasoning**: Ontology-based knowledge inference
513
+ - **Real-time Processing**: Fast detection suitable for commercial use
514
+
515
+ ### Detection Capabilities
516
+
517
+ The system can detect and classify:
518
+ - **Healthy mangoes**: No visible disease symptoms
519
+ - **Early disease**: Minor symptoms requiring monitoring
520
+ - **Moderate/Severe disease**: Clear symptoms requiring treatment
521
+ - **Critical disease**: Severe damage requiring disposal
522
+
523
+ ### Analysis Features
524
+
525
+ - **Disease Classification**: Specific disease type identification
526
+ - **Severity Assessment**: Quantitative severity percentage
527
+ - **Economic Impact**: Marketability scoring
528
+ - **Treatment Recommendations**: AI-generated suggestions
529
+ - **Quality Grading**: Commercial quality assessment
530
+
531
+ ### Usage Modes
532
+
533
+ 1. **Single Image**: Upload individual images for analysis
534
+ 2. **Batch Processing**: Process multiple images in ZIP format
535
+ 3. **Real-time Detection**: Live webcam analysis (requires setup)
536
+
537
+ ### Technical Details
538
+
539
+ - Built with Streamlit for web interface
540
+ - Semantic analysis using OWL-RL reasoning
541
+ - Computer vision with deep learning models
542
+ - Supports common image formats (JPG, PNG, BMP, TIFF)
543
+
544
+ ### Usage Tips
545
+
546
+ - Use high-quality, well-lit images for best results
547
+ - Ensure mango is clearly visible in the frame
548
+ - Multiple angles can provide more comprehensive analysis
549
+ - Regular monitoring helps track disease progression
550
+
551
+ ---
552
+
553
+ *For technical support or questions about the detection algorithms,
554
+ please refer to the system documentation.*
555
+ """)
556
+
557
+ # System status
558
+ st.subheader("System Status")
559
+
560
+ col1, col2, col3 = st.columns(3)
561
+
562
+ with col1:
563
+ if ANALYZER_AVAILABLE:
564
+ st.success("Analyzer Available")
565
+ else:
566
+ st.error("Analyzer Unavailable")
567
+
568
+ with col2:
569
+ st.info(f"Session: {datetime.now().strftime('%Y-%m-%d %H:%M')}")
570
+
571
+ with col3:
572
+ if 'analyzer' in st.session_state and st.session_state.analyzer:
573
+ st.success("System Ready")
574
+ else:
575
+ st.warning("System Not Ready")
576
+
577
+ if __name__ == "__main__":
578
+ main()