fouadmahmoud283-ai commited on
Commit
3fadcec
Β·
0 Parent(s):

Update streamlit app

Browse files
Files changed (5) hide show
  1. .gitattributes +35 -0
  2. Dockerfile +20 -0
  3. README.md +10 -0
  4. requirements.txt +14 -0
  5. src/streamlit_app.py +647 -0
.gitattributes ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
Dockerfile ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.13.5-slim
2
+
3
+ WORKDIR /app
4
+
5
+ RUN apt-get update && apt-get install -y \
6
+ build-essential \
7
+ curl \
8
+ git \
9
+ && rm -rf /var/lib/apt/lists/*
10
+
11
+ COPY requirements.txt ./
12
+ COPY src/ ./src/
13
+
14
+ RUN pip3 install -r requirements.txt
15
+
16
+ EXPOSE 8501
17
+
18
+ HEALTHCHECK CMD curl --fail http://localhost:8501/_stcore/health
19
+
20
+ ENTRYPOINT ["streamlit", "run", "src/streamlit_app.py", "--server.port=8501", "--server.address=0.0.0.0"]
README.md ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ title: Processing Image
2
+ emoji: πŸš€
3
+ colorFrom: red
4
+ colorTo: red
5
+ sdk: docker
6
+ app_port: 8501
7
+ tags:
8
+ - streamlit
9
+ pinned: false
10
+ short_description: Streamlit template space
requirements.txt ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ altair
2
+ pandas
3
+ streamlit
4
+ torch
5
+ torchvision
6
+ opencv-python-headless
7
+ Pillow
8
+ numpy
9
+ plotly
10
+ matplotlib
11
+ seaborn
12
+ ultralytics
13
+ av
14
+ aiortc
src/streamlit_app.py ADDED
@@ -0,0 +1,647 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import torch
3
+ import cv2
4
+ import numpy as np
5
+ from PIL import Image
6
+ import io
7
+ import time
8
+ import plotly.graph_objects as go
9
+ import plotly.express as px
10
+ import pandas as pd
11
+ from pathlib import Path
12
+ import tempfile
13
+ import os
14
+ import logging
15
+ import warnings
16
+
17
+ # Suppress WebRTC/asyncio warnings and errors
18
+ logging.getLogger('aioice').setLevel(logging.CRITICAL)
19
+ logging.getLogger('asyncio').setLevel(logging.CRITICAL)
20
+ logging.getLogger('streamlit_webrtc').setLevel(logging.ERROR)
21
+ warnings.filterwarnings('ignore', category=DeprecationWarning)
22
+ warnings.filterwarnings('ignore', category=FutureWarning)
23
+
24
+ # Page config
25
+ st.set_page_config(
26
+ page_title="🦽 AI Wheelchair Navigation System",
27
+ page_icon="🦽",
28
+ layout="wide",
29
+ initial_sidebar_state="expanded"
30
+ )
31
+
32
+ # Custom CSS for wheelchair theme
33
+ st.markdown("""
34
+ <style>
35
+ .main-header {
36
+ background: linear-gradient(90deg, #2E86AB 0%, #A23B72 50%, #F18F01 100%);
37
+ color: white;
38
+ padding: 2rem;
39
+ border-radius: 10px;
40
+ margin-bottom: 2rem;
41
+ text-align: center;
42
+ }
43
+
44
+ .metric-card {
45
+ background: #f8f9fa;
46
+ padding: 1rem;
47
+ border-radius: 10px;
48
+ border-left: 4px solid #2E86AB;
49
+ margin: 0.5rem 0;
50
+ }
51
+
52
+ .detection-box {
53
+ background: #e8f4f8;
54
+ padding: 1rem;
55
+ border-radius: 8px;
56
+ border: 1px solid #2E86AB;
57
+ margin: 0.5rem 0;
58
+ }
59
+
60
+ .safety-alert {
61
+ background: #fff3cd;
62
+ color: #856404;
63
+ padding: 1rem;
64
+ border-radius: 8px;
65
+ border-left: 4px solid #ffc107;
66
+ margin: 1rem 0;
67
+ }
68
+
69
+ .success-alert {
70
+ background: #d4edda;
71
+ color: #155724;
72
+ padding: 1rem;
73
+ border-radius: 8px;
74
+ border-left: 4px solid #28a745;
75
+ margin: 1rem 0;
76
+ }
77
+
78
+ .wheelchair-icon {
79
+ font-size: 2rem;
80
+ color: #2E86AB;
81
+ }
82
+
83
+ .stButton > button {
84
+ background: linear-gradient(90deg, #2E86AB, #A23B72);
85
+ color: white;
86
+ border-radius: 20px;
87
+ border: none;
88
+ padding: 0.5rem 2rem;
89
+ font-weight: bold;
90
+ }
91
+
92
+ .stSelectbox > div > div {
93
+ border-radius: 10px;
94
+ }
95
+ </style>
96
+ """, unsafe_allow_html=True)
97
+
98
+ # Initialize session state
99
+ if 'model' not in st.session_state:
100
+ st.session_state.model = None
101
+ if 'detection_history' not in st.session_state:
102
+ st.session_state.detection_history = []
103
+
104
+ # Wheelchair-relevant classes from COCO
105
+ WHEELCHAIR_CLASSES = {
106
+ 0: 'person', # People to avoid/navigate around
107
+ 1: 'bicycle', # Other mobility devices
108
+ 2: 'car', # Vehicles to avoid
109
+ 3: 'motorcycle', # Vehicles to avoid
110
+ 5: 'bus', # Large vehicles
111
+ 7: 'truck', # Large vehicles
112
+ 9: 'traffic light', # Navigation signals
113
+ 11: 'stop sign', # Navigation signals
114
+ 24: 'backpack', # Personal items/obstacles
115
+ 26: 'handbag', # Personal items/obstacles
116
+ 56: 'chair', # Furniture/obstacles
117
+ 58: 'potted plant' # Environmental obstacles
118
+ }
119
+
120
+ CLASS_COLORS = {
121
+ 'person': '#FF6B6B',
122
+ 'bicycle': '#4ECDC4',
123
+ 'car': '#45B7D1',
124
+ 'motorcycle': '#96CEB4',
125
+ 'bus': '#FECA57',
126
+ 'truck': '#FF9F43',
127
+ 'traffic light': '#6C5CE7',
128
+ 'stop sign': '#FD79A8',
129
+ 'chair': '#A0E7E5',
130
+ 'backpack': '#DDA0DD',
131
+ 'handbag': '#F7DC6F',
132
+ 'potted plant': '#82E0AA'
133
+ }
134
+
135
+ @st.cache_resource
136
+ def load_model(confidence_threshold=0.5):
137
+ """Load YOLOv5 model with caching"""
138
+ try:
139
+ # Try to load from local path first (for development)
140
+ model_paths = [
141
+ "wheelchair_runs/wheelchair_exp5/weights/best.pt",
142
+ "wheelchair_runs/wheelchair_exp/weights/best.pt",
143
+ "best.pt" # Fallback
144
+ ]
145
+
146
+ model = None
147
+ for path in model_paths:
148
+ if os.path.exists(path):
149
+ model = torch.hub.load('ultralytics/yolov5', 'custom', path=path, trust_repo=True)
150
+ break
151
+
152
+ # If no local model, load pretrained YOLOv5s
153
+ if model is None:
154
+ model = torch.hub.load('ultralytics/yolov5', 'yolov5s', pretrained=True, trust_repo=True)
155
+ st.warning("⚠️ Using pretrained YOLOv5s model. For best wheelchair navigation, upload your trained model.")
156
+
157
+ model.conf = confidence_threshold
158
+ model.iou = 0.45
159
+ return model
160
+ except Exception as e:
161
+ st.error(f"Error loading model: {e}")
162
+ return None
163
+
164
+ def get_navigation_advice(detections, image_width=640):
165
+ """Generate navigation advice based on detections"""
166
+ advice = []
167
+ safety_level = "🟒 SAFE"
168
+
169
+ if detections is None or len(detections) == 0:
170
+ return ["βœ… Clear path ahead"], safety_level
171
+
172
+ critical_detections = 0
173
+
174
+ for _, detection in detections.iterrows():
175
+ class_id = int(detection['class'])
176
+ class_name = detection['name']
177
+ confidence = detection['confidence']
178
+ x_center = (detection['xmin'] + detection['xmax']) / 2
179
+ y_center = (detection['ymin'] + detection['ymax']) / 2
180
+
181
+ # Determine position relative to wheelchair
182
+ if x_center < image_width * 0.33:
183
+ position = "left"
184
+ elif x_center > image_width * 0.67:
185
+ position = "right"
186
+ else:
187
+ position = "ahead"
188
+ critical_detections += 1
189
+
190
+ # Generate specific advice based on object type and position
191
+ if class_name == 'person':
192
+ if position == "ahead":
193
+ advice.append(f"⚠️ PERSON DETECTED AHEAD - STOP and wait for clear path")
194
+ safety_level = "πŸ”΄ CRITICAL"
195
+ else:
196
+ advice.append(f"πŸ‘€ Person on {position} (conf: {confidence:.0%})")
197
+ if safety_level == "🟒 SAFE":
198
+ safety_level = "🟑 CAUTION"
199
+
200
+ elif class_name in ['car', 'truck', 'bus', 'motorcycle']:
201
+ advice.append(f"πŸš— {class_name.title()} {position} - proceed with extreme caution")
202
+ safety_level = "πŸ”΄ CRITICAL" if position == "ahead" else "🟑 CAUTION"
203
+
204
+ elif class_name in ['traffic light', 'stop sign']:
205
+ advice.append(f"🚦 {class_name.replace('_', ' ').title()} detected - follow traffic rules")
206
+
207
+ elif class_name == 'chair':
208
+ advice.append(f"πŸͺ‘ Chair detected on {position} - navigate around")
209
+ if position == "ahead":
210
+ safety_level = "🟑 CAUTION"
211
+
212
+ elif class_name in ['backpack', 'handbag']:
213
+ advice.append(f"πŸŽ’ Personal item on {position} - person nearby")
214
+
215
+ elif class_name == 'potted plant':
216
+ advice.append(f"πŸͺ΄ Obstacle on {position} - adjust path")
217
+
218
+ if critical_detections > 2:
219
+ safety_level = "πŸ”΄ CRITICAL"
220
+ advice.insert(0, "⚠️ MULTIPLE OBSTACLES AHEAD - STOP AND REASSESS")
221
+
222
+ return advice[:5], safety_level # Limit to top 5 pieces of advice
223
+
224
+ def process_image(image, model, conf_threshold):
225
+ """Process image and return results"""
226
+ if model is None:
227
+ return None, None, []
228
+
229
+ # Run inference
230
+ results = model(image)
231
+
232
+ # Get detections
233
+ detections = results.pandas().xyxy[0]
234
+
235
+ # Filter to wheelchair-relevant classes
236
+ relevant_detections = detections[detections['name'].isin(WHEELCHAIR_CLASSES.values())]
237
+
238
+ # Get rendered image
239
+ rendered_img = results.render()[0]
240
+ rendered_img = cv2.cvtColor(rendered_img, cv2.COLOR_BGR2RGB)
241
+
242
+ return rendered_img, relevant_detections, results
243
+
244
+ def create_detection_chart(detections):
245
+ """Create a bar chart of detections"""
246
+ if detections is None or len(detections) == 0:
247
+ return None
248
+
249
+ detection_counts = detections['name'].value_counts()
250
+
251
+ fig = px.bar(
252
+ x=detection_counts.index,
253
+ y=detection_counts.values,
254
+ color=detection_counts.index,
255
+ color_discrete_map=CLASS_COLORS,
256
+ title="πŸ“Š Detected Objects Count",
257
+ labels={'x': 'Object Type', 'y': 'Count'}
258
+ )
259
+
260
+ fig.update_layout(
261
+ showlegend=False,
262
+ plot_bgcolor='rgba(0,0,0,0)',
263
+ paper_bgcolor='rgba(0,0,0,0)',
264
+ font=dict(size=12),
265
+ title_font=dict(size=16, color='#2E86AB')
266
+ )
267
+
268
+ return fig
269
+
270
+ def create_confidence_chart(detections):
271
+ """Create a confidence score visualization"""
272
+ if detections is None or len(detections) == 0:
273
+ return None
274
+
275
+ fig = px.scatter(
276
+ detections,
277
+ x='name',
278
+ y='confidence',
279
+ size='confidence',
280
+ color='name',
281
+ color_discrete_map=CLASS_COLORS,
282
+ title="🎯 Detection Confidence Scores",
283
+ labels={'confidence': 'Confidence Score', 'name': 'Object Type'}
284
+ )
285
+
286
+ fig.update_layout(
287
+ showlegend=False,
288
+ plot_bgcolor='rgba(0,0,0,0)',
289
+ paper_bgcolor='rgba(0,0,0,0)',
290
+ font=dict(size=12),
291
+ title_font=dict(size=16, color='#2E86AB')
292
+ )
293
+
294
+ return fig
295
+
296
+ # Main app
297
+ def main():
298
+ # Header
299
+ st.markdown("""
300
+ <div class="main-header">
301
+ <h1>🦽 AI Wheelchair Navigation System</h1>
302
+ <p>Intelligent Computer Vision for Safe Wheelchair Navigation</p>
303
+ <p><strong>Graduation Project</strong> | YOLOv5 Object Detection | Raspberry Pi Optimized</p>
304
+ </div>
305
+ """, unsafe_allow_html=True)
306
+
307
+ # Sidebar
308
+ with st.sidebar:
309
+ st.markdown("### πŸ”§ Model Configuration")
310
+
311
+ # Model settings
312
+ conf_threshold = st.slider(
313
+ "Confidence Threshold",
314
+ min_value=0.1,
315
+ max_value=1.0,
316
+ value=0.5,
317
+ step=0.1,
318
+ help="Minimum confidence for object detection"
319
+ )
320
+
321
+ st.markdown("### πŸ“Š Model Performance")
322
+ st.markdown("""
323
+ <div class="metric-card">
324
+ <strong>🎯 Overall Accuracy:</strong> 87.5% mAP@0.5<br>
325
+ <strong>πŸ‘€ Person Detection:</strong> 84.4%<br>
326
+ <strong>πŸͺ‘ Chair Detection:</strong> 93.9%<br>
327
+ <strong>πŸš— Vehicle Detection:</strong> 56.3%<br>
328
+ <strong>βš–οΈ Model Size:</strong> 14.7 MB
329
+ </div>
330
+ """, unsafe_allow_html=True)
331
+
332
+ st.markdown("### 🎯 Wheelchair-Relevant Objects")
333
+ for class_id, class_name in WHEELCHAIR_CLASSES.items():
334
+ color = CLASS_COLORS.get(class_name, '#808080')
335
+ st.markdown(f'<span style="color: {color}; font-weight: bold;">●</span> {class_name.title()}', unsafe_allow_html=True)
336
+
337
+ # Main content tabs
338
+ tab1, tab2, tab3, tab4 = st.tabs(["πŸ“Έ Live Detection", "πŸ“Š Analytics", "ℹ️ About", "πŸš€ Deployment"])
339
+
340
+ with tab1:
341
+ col1, col2 = st.columns([2, 1])
342
+
343
+ with col1:
344
+ st.markdown("### πŸ“· Upload Image for Detection")
345
+ uploaded_file = st.file_uploader(
346
+ "Choose an image...",
347
+ type=['jpg', 'jpeg', 'png'],
348
+ help="Upload an image to test wheelchair navigation detection"
349
+ )
350
+
351
+ # Demo images
352
+ st.markdown("### 🎬 Try Demo Images")
353
+ demo_col1, demo_col2, demo_col3 = st.columns(3)
354
+
355
+ with demo_col1:
356
+ if st.button("πŸͺ Indoor Scene"):
357
+ # You would replace this with actual demo images
358
+ st.info("Demo: Indoor navigation scenario")
359
+
360
+ with demo_col2:
361
+ if st.button("πŸ™οΈ Outdoor Scene"):
362
+ st.info("Demo: Outdoor navigation scenario")
363
+
364
+ with demo_col3:
365
+ if st.button("🚢 Crowded Area"):
366
+ st.info("Demo: Crowded area navigation")
367
+
368
+ with col2:
369
+ st.markdown("### πŸ›‘οΈ Safety Status")
370
+ safety_placeholder = st.empty()
371
+
372
+ st.markdown("### 🧭 Navigation Advice")
373
+ advice_placeholder = st.empty()
374
+
375
+ # Process uploaded image
376
+ if uploaded_file is not None:
377
+ # Load and display original image
378
+ image = Image.open(uploaded_file)
379
+
380
+ col1, col2 = st.columns(2)
381
+
382
+ with col1:
383
+ st.markdown("#### πŸ“Έ Original Image")
384
+ st.image(image, use_column_width=True)
385
+
386
+ # Load model
387
+ if st.session_state.model is None:
388
+ with st.spinner("πŸ€– Loading AI model..."):
389
+ st.session_state.model = load_model(conf_threshold)
390
+
391
+ if st.session_state.model is not None:
392
+ # Process image
393
+ with st.spinner("πŸ” Analyzing image for obstacles..."):
394
+ start_time = time.time()
395
+ rendered_img, detections, results = process_image(image, st.session_state.model, conf_threshold)
396
+ processing_time = time.time() - start_time
397
+
398
+ with col2:
399
+ st.markdown("#### 🎯 Detection Results")
400
+ if rendered_img is not None:
401
+ st.image(rendered_img, use_column_width=True)
402
+
403
+ # Generate navigation advice
404
+ advice, safety_level = get_navigation_advice(detections, image.width)
405
+
406
+ # Update safety status
407
+ with safety_placeholder.container():
408
+ if "CRITICAL" in safety_level:
409
+ st.markdown(f'<div class="safety-alert"><strong>{safety_level}</strong></div>', unsafe_allow_html=True)
410
+ elif "CAUTION" in safety_level:
411
+ st.markdown(f'<div style="background: #fff3cd; color: #856404; padding: 1rem; border-radius: 8px; border-left: 4px solid #ffc107;"><strong>{safety_level}</strong></div>', unsafe_allow_html=True)
412
+ else:
413
+ st.markdown(f'<div class="success-alert"><strong>{safety_level}</strong></div>', unsafe_allow_html=True)
414
+
415
+ # Display navigation advice
416
+ with advice_placeholder.container():
417
+ for advice_text in advice:
418
+ st.markdown(f'<div class="detection-box">{advice_text}</div>', unsafe_allow_html=True)
419
+
420
+ # Performance metrics
421
+ st.markdown("### ⚑ Performance Metrics")
422
+ perf_col1, perf_col2, perf_col3, perf_col4 = st.columns(4)
423
+
424
+ with perf_col1:
425
+ st.metric("⏱️ Processing Time", f"{processing_time:.2f}s")
426
+
427
+ with perf_col2:
428
+ fps = 1 / processing_time if processing_time > 0 else 0
429
+ st.metric("🎬 Estimated FPS", f"{fps:.1f}")
430
+
431
+ with perf_col3:
432
+ total_detections = len(detections) if detections is not None else 0
433
+ st.metric("πŸ” Objects Detected", total_detections)
434
+
435
+ with perf_col4:
436
+ relevant_count = len(detections) if detections is not None else 0
437
+ st.metric("🎯 Relevant Objects", relevant_count)
438
+
439
+ # Detailed detection results
440
+ if detections is not None and len(detections) > 0:
441
+ st.markdown("### πŸ“‹ Detailed Detection Results")
442
+
443
+ # Create a formatted dataframe
444
+ display_df = detections[['name', 'confidence', 'xmin', 'ymin', 'xmax', 'ymax']].copy()
445
+ display_df['confidence'] = display_df['confidence'].apply(lambda x: f"{x:.1%}")
446
+ display_df.columns = ['Object', 'Confidence', 'X Min', 'Y Min', 'X Max', 'Y Max']
447
+
448
+ st.dataframe(display_df, use_container_width=True)
449
+
450
+ with tab2:
451
+ st.markdown("### πŸ“Š Detection Analytics")
452
+
453
+ if uploaded_file is not None and 'detections' in locals() and detections is not None:
454
+ col1, col2 = st.columns(2)
455
+
456
+ with col1:
457
+ chart1 = create_detection_chart(detections)
458
+ if chart1:
459
+ st.plotly_chart(chart1, use_container_width=True)
460
+
461
+ with col2:
462
+ chart2 = create_confidence_chart(detections)
463
+ if chart2:
464
+ st.plotly_chart(chart2, use_container_width=True)
465
+
466
+ # Detection statistics
467
+ st.markdown("### πŸ“ˆ Statistics")
468
+ if len(detections) > 0:
469
+ stats_col1, stats_col2, stats_col3 = st.columns(3)
470
+
471
+ with stats_col1:
472
+ avg_conf = detections['confidence'].mean()
473
+ st.metric("πŸ“Š Average Confidence", f"{avg_conf:.1%}")
474
+
475
+ with stats_col2:
476
+ max_conf = detections['confidence'].max()
477
+ st.metric("🎯 Highest Confidence", f"{max_conf:.1%}")
478
+
479
+ with stats_col3:
480
+ unique_classes = detections['name'].nunique()
481
+ st.metric("🏷️ Unique Object Types", unique_classes)
482
+ else:
483
+ st.info("πŸ“Έ Upload an image in the 'Live Detection' tab to see analytics")
484
+
485
+ with tab3:
486
+ st.markdown("### ℹ️ About This System")
487
+
488
+ col1, col2 = st.columns([2, 1])
489
+
490
+ with col1:
491
+ st.markdown("""
492
+ #### 🦽 AI Wheelchair Navigation System
493
+
494
+ This intelligent computer vision system is designed to assist wheelchair users with safe navigation by detecting and identifying potential obstacles, people, vehicles, and navigation signals in real-time.
495
+
496
+ **🎯 Key Features:**
497
+ - **Real-time Object Detection**: Identifies 12 wheelchair-relevant object types
498
+ - **Safety Warnings**: Provides immediate alerts for potential hazards
499
+ - **Navigation Guidance**: Offers contextual advice for safe path planning
500
+ - **Raspberry Pi Optimized**: Lightweight model for edge deployment
501
+ - **High Accuracy**: 87.5% mAP@0.5 overall accuracy
502
+
503
+ **πŸ”§ Technical Specifications:**
504
+ - **Model**: YOLOv5s (Small) - optimized for speed and accuracy
505
+ - **Input Size**: 416x416 pixels
506
+ - **Model Size**: 14.7 MB (perfect for embedded systems)
507
+ - **Target Platform**: Raspberry Pi 4
508
+ - **Processing Speed**: 5-10 FPS on Raspberry Pi
509
+
510
+ **πŸŽ“ Graduation Project Context:**
511
+ This system represents a comprehensive computer vision solution for assistive technology, demonstrating:
512
+ - Advanced deep learning implementation
513
+ - Edge computing optimization
514
+ - Real-world application development
515
+ - Safety-critical system design
516
+ """)
517
+
518
+ with col2:
519
+ st.markdown("""
520
+ #### πŸ† Model Performance
521
+
522
+ **Overall Metrics:**
523
+ - mAP@0.5: 87.5%
524
+ - mAP@0.5:0.95: 63.6%
525
+ - Precision: 88.6%
526
+ - Recall: 80.8%
527
+
528
+ **Class-Specific Performance:**
529
+ - Person: 84.4% mAP
530
+ - Chair: 93.9% mAP
531
+ - Vehicle: 56.3% mAP
532
+ - Bicycle: 80.9% mAP
533
+
534
+ **πŸ”’ Safety Features:**
535
+ - Emergency obstacle detection
536
+ - Multi-level alert system
537
+ - Contextual navigation advice
538
+ - Real-time processing
539
+ """)
540
+
541
+ st.markdown("### πŸ› οΈ Technology Stack")
542
+
543
+ tech_col1, tech_col2, tech_col3, tech_col4 = st.columns(4)
544
+
545
+ with tech_col1:
546
+ st.markdown("""
547
+ **🧠 AI/ML**
548
+ - YOLOv5
549
+ - PyTorch
550
+ - OpenCV
551
+ - NumPy
552
+ """)
553
+
554
+ with tech_col2:
555
+ st.markdown("""
556
+ **🌐 Web App**
557
+ - Streamlit
558
+ - Plotly
559
+ - PIL/Pillow
560
+ - Pandas
561
+ """)
562
+
563
+ with tech_col3:
564
+ st.markdown("""
565
+ **⚑ Deployment**
566
+ - Hugging Face Spaces
567
+ - Docker
568
+ - Git LFS
569
+ - ONNX (optional)
570
+ """)
571
+
572
+ with tech_col4:
573
+ st.markdown("""
574
+ **πŸ”§ Hardware**
575
+ - Raspberry Pi 4
576
+ - USB/Pi Camera
577
+ - MicroSD Storage
578
+ - Power Supply
579
+ """)
580
+
581
+ with tab4:
582
+ st.markdown("### πŸš€ Deployment Information")
583
+
584
+ col1, col2 = st.columns(2)
585
+
586
+ with col1:
587
+ st.markdown("""
588
+ #### πŸ“¦ Hugging Face Spaces Deployment
589
+
590
+ This application is deployed on Hugging Face Spaces, providing:
591
+ - **Free hosting** for demonstration purposes
592
+ - **Easy sharing** with project evaluators
593
+ - **Scalable infrastructure** for multiple users
594
+ - **Integrated CI/CD** for automatic updates
595
+
596
+ **πŸ”— Deployment Features:**
597
+ - Real-time inference on uploaded images
598
+ - Interactive web interface
599
+ - Performance analytics and visualization
600
+ - Mobile-responsive design
601
+ """)
602
+
603
+ with col2:
604
+ st.markdown("""
605
+ #### 🏠 Local/Raspberry Pi Deployment
606
+
607
+ For real wheelchair deployment:
608
+
609
+ 1. **Download the deployment package**
610
+ 2. **Transfer to Raspberry Pi**
611
+ 3. **Install dependencies**
612
+ 4. **Connect camera**
613
+ 5. **Run inference script**
614
+
615
+ **πŸ“‹ Requirements:**
616
+ - Raspberry Pi 4 (4GB RAM recommended)
617
+ - Python 3.7+
618
+ - PyTorch (CPU version)
619
+ - USB Camera or Pi Camera
620
+ """)
621
+
622
+ st.markdown("### πŸ’» Code Repository")
623
+ st.markdown("""
624
+ **πŸ“ Project Structure:**
625
+ ```
626
+ wheelchair_deployment/
627
+ β”œβ”€β”€ wheelchair_model.pt # Trained model weights
628
+ β”œβ”€β”€ wheelchair_inference.py # Raspberry Pi inference script
629
+ β”œβ”€β”€ requirements_rpi.txt # Dependencies
630
+ β”œβ”€β”€ README_deployment.md # Setup instructions
631
+ └── wheelchair_config.yaml # Model configuration
632
+ ```
633
+ """)
634
+
635
+ st.markdown("### 🀝 Integration Guidelines")
636
+ st.markdown("""
637
+ **For Wheelchair Integration:**
638
+
639
+ 1. **Motor Control Interface**: Connect detection results to wheelchair motor control system
640
+ 2. **Safety Protocols**: Implement emergency stop and collision avoidance
641
+ 3. **User Interface**: Add audio/visual feedback for navigation guidance
642
+ 4. **Sensor Fusion**: Combine with ultrasonic/LiDAR sensors for enhanced safety
643
+ 5. **Custom Training**: Collect and label wheelchair-specific navigation data
644
+ """)
645
+
646
+ if __name__ == "__main__":
647
+ main()