Spaces:
Runtime error
Runtime error
fouadmahmoud283-ai commited on
Commit ยท
bdd5f33
1
Parent(s): bbb296c
fixing camera n1235
Browse files- src/streamlit_app.py +120 -1
src/streamlit_app.py
CHANGED
|
@@ -112,6 +112,10 @@ if 'current_image' not in st.session_state:
|
|
| 112 |
st.session_state.current_image = None
|
| 113 |
if 'demo_selected' not in st.session_state:
|
| 114 |
st.session_state.demo_selected = False
|
|
|
|
|
|
|
|
|
|
|
|
|
| 115 |
|
| 116 |
# Demo images URLs (publicly accessible images)
|
| 117 |
DEMO_IMAGES = {
|
|
@@ -271,6 +275,71 @@ def process_image(image, model, conf_threshold):
|
|
| 271 |
|
| 272 |
return rendered_img, relevant_detections, results
|
| 273 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 274 |
def create_detection_chart(detections):
|
| 275 |
"""Create a bar chart of detections"""
|
| 276 |
if detections is None or len(detections) == 0:
|
|
@@ -417,13 +486,21 @@ def main():
|
|
| 417 |
|
| 418 |
with col1:
|
| 419 |
st.markdown("### ๐ท Upload Image for Detection")
|
| 420 |
-
|
| 421 |
uploaded_file = st.file_uploader(
|
| 422 |
"Choose an image...",
|
| 423 |
type=['jpg', 'jpeg', 'png', 'bmp'],
|
| 424 |
help="Upload an image to test wheelchair navigation detection",
|
| 425 |
key="image_uploader"
|
| 426 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 427 |
|
| 428 |
# Demo images buttons
|
| 429 |
st.markdown("### ๐ฌ Or Try Demo Images")
|
|
@@ -466,6 +543,48 @@ def main():
|
|
| 466 |
st.session_state.current_image = image
|
| 467 |
elif st.session_state.demo_selected and st.session_state.current_image is not None:
|
| 468 |
image = st.session_state.current_image
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 469 |
|
| 470 |
if image is not None:
|
| 471 |
|
|
|
|
| 112 |
st.session_state.current_image = None
|
| 113 |
if 'demo_selected' not in st.session_state:
|
| 114 |
st.session_state.demo_selected = False
|
| 115 |
+
if 'processed_video_path' not in st.session_state:
|
| 116 |
+
st.session_state.processed_video_path = None
|
| 117 |
+
if 'video_stats' not in st.session_state:
|
| 118 |
+
st.session_state.video_stats = None
|
| 119 |
|
| 120 |
# Demo images URLs (publicly accessible images)
|
| 121 |
DEMO_IMAGES = {
|
|
|
|
| 275 |
|
| 276 |
return rendered_img, relevant_detections, results
|
| 277 |
|
| 278 |
+
def process_video(video_path, model, conf_threshold, frame_skip=1):
|
| 279 |
+
"""Process video and return output path + stats."""
|
| 280 |
+
if model is None:
|
| 281 |
+
return None, None
|
| 282 |
+
|
| 283 |
+
cap = cv2.VideoCapture(video_path)
|
| 284 |
+
if not cap.isOpened():
|
| 285 |
+
return None, None
|
| 286 |
+
|
| 287 |
+
fps = cap.get(cv2.CAP_PROP_FPS) or 24
|
| 288 |
+
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
|
| 289 |
+
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
|
| 290 |
+
|
| 291 |
+
output_fd, output_path = tempfile.mkstemp(suffix=".mp4")
|
| 292 |
+
os.close(output_fd)
|
| 293 |
+
|
| 294 |
+
fourcc = cv2.VideoWriter_fourcc(*"mp4v")
|
| 295 |
+
writer = cv2.VideoWriter(output_path, fourcc, fps, (width, height))
|
| 296 |
+
|
| 297 |
+
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) or 0
|
| 298 |
+
processed_frames = 0
|
| 299 |
+
detection_counts = {}
|
| 300 |
+
|
| 301 |
+
progress = st.progress(0, text="Processing video frames...")
|
| 302 |
+
|
| 303 |
+
frame_index = 0
|
| 304 |
+
while True:
|
| 305 |
+
ret, frame = cap.read()
|
| 306 |
+
if not ret:
|
| 307 |
+
break
|
| 308 |
+
|
| 309 |
+
frame_index += 1
|
| 310 |
+
if frame_skip > 1 and frame_index % frame_skip != 0:
|
| 311 |
+
writer.write(frame)
|
| 312 |
+
continue
|
| 313 |
+
|
| 314 |
+
img_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
| 315 |
+
model.conf = conf_threshold
|
| 316 |
+
results = model(img_rgb)
|
| 317 |
+
|
| 318 |
+
detections = results.pandas().xyxy[0]
|
| 319 |
+
relevant = detections[detections['name'].isin(WHEELCHAIR_CLASSES.values())]
|
| 320 |
+
|
| 321 |
+
for name in relevant['name'].tolist():
|
| 322 |
+
detection_counts[name] = detection_counts.get(name, 0) + 1
|
| 323 |
+
|
| 324 |
+
rendered_frame = results.render()[0]
|
| 325 |
+
writer.write(rendered_frame)
|
| 326 |
+
|
| 327 |
+
processed_frames += 1
|
| 328 |
+
if total_frames > 0:
|
| 329 |
+
progress.progress(min(processed_frames / total_frames, 1.0))
|
| 330 |
+
|
| 331 |
+
progress.empty()
|
| 332 |
+
cap.release()
|
| 333 |
+
writer.release()
|
| 334 |
+
|
| 335 |
+
stats = {
|
| 336 |
+
"total_frames": total_frames,
|
| 337 |
+
"processed_frames": processed_frames,
|
| 338 |
+
"detection_counts": detection_counts
|
| 339 |
+
}
|
| 340 |
+
|
| 341 |
+
return output_path, stats
|
| 342 |
+
|
| 343 |
def create_detection_chart(detections):
|
| 344 |
"""Create a bar chart of detections"""
|
| 345 |
if detections is None or len(detections) == 0:
|
|
|
|
| 486 |
|
| 487 |
with col1:
|
| 488 |
st.markdown("### ๐ท Upload Image for Detection")
|
| 489 |
+
|
| 490 |
uploaded_file = st.file_uploader(
|
| 491 |
"Choose an image...",
|
| 492 |
type=['jpg', 'jpeg', 'png', 'bmp'],
|
| 493 |
help="Upload an image to test wheelchair navigation detection",
|
| 494 |
key="image_uploader"
|
| 495 |
)
|
| 496 |
+
|
| 497 |
+
st.markdown("### ๐ฅ Upload Video for Detection")
|
| 498 |
+
uploaded_video = st.file_uploader(
|
| 499 |
+
"Choose a video...",
|
| 500 |
+
type=['mp4', 'avi', 'mov', 'mkv'],
|
| 501 |
+
help="Upload a video to run obstacle detection",
|
| 502 |
+
key="video_uploader"
|
| 503 |
+
)
|
| 504 |
|
| 505 |
# Demo images buttons
|
| 506 |
st.markdown("### ๐ฌ Or Try Demo Images")
|
|
|
|
| 543 |
st.session_state.current_image = image
|
| 544 |
elif st.session_state.demo_selected and st.session_state.current_image is not None:
|
| 545 |
image = st.session_state.current_image
|
| 546 |
+
|
| 547 |
+
# Process uploaded video
|
| 548 |
+
if uploaded_video is not None:
|
| 549 |
+
st.session_state.demo_selected = False
|
| 550 |
+
|
| 551 |
+
if st.session_state.model is None:
|
| 552 |
+
with st.spinner("๐ค Loading AI model..."):
|
| 553 |
+
st.session_state.model = load_model(conf_threshold)
|
| 554 |
+
|
| 555 |
+
if st.button("โถ๏ธ Run Video Detection", use_container_width=True):
|
| 556 |
+
with tempfile.NamedTemporaryFile(delete=False, suffix=Path(uploaded_video.name).suffix) as tmp:
|
| 557 |
+
tmp.write(uploaded_video.getbuffer())
|
| 558 |
+
tmp_path = tmp.name
|
| 559 |
+
|
| 560 |
+
with st.spinner("๐ Processing video for obstacles..."):
|
| 561 |
+
output_path, stats = process_video(tmp_path, st.session_state.model, conf_threshold, frame_skip=1)
|
| 562 |
+
|
| 563 |
+
st.session_state.processed_video_path = output_path
|
| 564 |
+
st.session_state.video_stats = stats
|
| 565 |
+
|
| 566 |
+
try:
|
| 567 |
+
os.remove(tmp_path)
|
| 568 |
+
except Exception:
|
| 569 |
+
pass
|
| 570 |
+
|
| 571 |
+
if st.session_state.processed_video_path:
|
| 572 |
+
st.markdown("### ๐ฌ Processed Video")
|
| 573 |
+
with open(st.session_state.processed_video_path, "rb") as f:
|
| 574 |
+
st.video(f.read())
|
| 575 |
+
|
| 576 |
+
if st.session_state.video_stats:
|
| 577 |
+
st.markdown("### ๐ Video Detection Summary")
|
| 578 |
+
stats = st.session_state.video_stats
|
| 579 |
+
st.metric("๐๏ธ Total Frames", stats.get("total_frames", 0))
|
| 580 |
+
st.metric("โ
Processed Frames", stats.get("processed_frames", 0))
|
| 581 |
+
|
| 582 |
+
if stats.get("detection_counts"):
|
| 583 |
+
counts_df = pd.DataFrame(
|
| 584 |
+
sorted(stats["detection_counts"].items(), key=lambda x: x[1], reverse=True),
|
| 585 |
+
columns=["Object", "Count"]
|
| 586 |
+
)
|
| 587 |
+
st.dataframe(counts_df, use_container_width=True)
|
| 588 |
|
| 589 |
if image is not None:
|
| 590 |
|