import time from typing import Optional import cv2 import numpy as np import streamlit as st from PIL import Image def streamlit_camera_capture() -> Optional[np.ndarray]: """Capture a single frame using Streamlit's native camera input. Returns: np.ndarray: BGR image array ready for OpenCV processing, or None if no capture """ camera_image = st.camera_input("📷 Capture frame for detection") if camera_image is not None: # Convert to OpenCV format img = Image.open(camera_image) img_array = np.array(img) img_bgr = cv2.cvtColor(img_array, cv2.COLOR_RGB2BGR) st.success("✅ Frame captured successfully!") return img_bgr else: st.info("👆 Click the camera button above to capture a frame") return None def streamlit_camera_preview() -> None: """Show a preview of the webcam using Streamlit's native camera.""" st.subheader("🎥 Webcam Preview") camera_image = st.camera_input("📹 Live webcam preview") if camera_image is not None: img = Image.open(camera_image) img_array = np.array(img) st.success("✅ Webcam is working!") st.image(img_array, caption="Live Preview", use_container_width=True) # Show frame info with st.expander("Frame Information"): st.write(f"**Resolution:** {img_array.shape[1]}x{img_array.shape[0]}") st.write(f"**Channels:** {img_array.shape[2]}") st.write("**Format:** RGB (Streamlit)") # Convert to BGR for OpenCV compatibility st.write("**OpenCV Format:** BGR") else: st.info("👆 Click the camera button above to see live preview") def streamlit_camera_test() -> bool: """Test if webcam is accessible using Streamlit's native camera. Returns: bool: True if webcam is accessible, False otherwise """ st.info("🔍 Testing webcam access with Streamlit...") camera_image = st.camera_input("📷 Test webcam access") if camera_image is not None: img = Image.open(camera_image) img_array = np.array(img) st.success("✅ Webcam is accessible!") st.image(img_array, caption="Test Capture", use_container_width=True) # Cache success in session state if hasattr(st, "session_state"): st.session_state.webcam_accessible = True st.session_state.last_test_time = time.time() return True else: st.error("❌ Webcam not accessible. Please check:") st.markdown(""" **macOS Users:** - Go to **System Settings → Privacy & Security → Camera** - Make sure your browser has camera access enabled - Refresh the page and try again **All Users:** - Make sure no other application is using the camera - Try refreshing the page - Check browser camera permissions """) # Cache failure in session state if hasattr(st, "session_state"): st.session_state.webcam_accessible = False return False def streamlit_camera_continuous_detection( num_frames: int = 10, detection_callback=None ) -> list[np.ndarray]: """Capture multiple frames using Streamlit's camera for continuous processing. Args: num_frames: Number of frames to capture detection_callback: Optional function to process each frame Returns: list[np.ndarray]: List of processed frames """ st.subheader(f"🎥 Continuous Detection ({num_frames} frames)") frames = [] progress_bar = st.progress(0) status_placeholder = st.empty() results_placeholder = st.empty() for i in range(num_frames): camera_image = st.camera_input( f"Frame {i + 1}/{num_frames}", key=f"continuous_{i}" ) if camera_image is not None: img = Image.open(camera_image) img_array = np.array(img) img_bgr = cv2.cvtColor(img_array, cv2.COLOR_RGB2BGR) # Process frame if callback provided if detection_callback: with st.spinner(f"Processing frame {i + 1}..."): processed_frame = detection_callback(img_bgr) frames.append(processed_frame) # Show result processed_rgb = cv2.cvtColor(processed_frame, cv2.COLOR_BGR2RGB) results_placeholder.image( processed_rgb, caption=f"Detection Result {i + 1}" ) else: frames.append(img_bgr) results_placeholder.image(img_array, caption=f"Frame {i + 1}") # Update progress progress_bar.progress((i + 1) / num_frames) status_placeholder.info(f"📹 Processed frame {i + 1}/{num_frames}") else: st.warning(f"⚠️ Frame {i + 1} not captured") break if frames: st.success(f"✅ Successfully processed {len(frames)} frames!") return frames else: st.error("❌ No frames processed") return [] def get_camera_status() -> dict: """Get current camera status from session state. Returns: dict: Camera status information """ if not hasattr(st, "session_state"): return {"accessible": False, "last_test": None} return { "accessible": getattr(st.session_state, "webcam_accessible", False), "last_test": getattr(st.session_state, "last_test_time", None), } def ensure_camera_released() -> None: """Ensure camera resources are released (placeholder for compatibility).""" # Streamlit handles camera resources automatically # This function is kept for compatibility with existing code pass def setup_webcam_properties(cap: cv2.VideoCapture) -> None: """Set optimal properties for webcam capture (placeholder for compatibility).""" # Streamlit handles camera properties automatically # This function is kept for compatibility with existing code pass def preview_webcam(camera_index: int) -> None: """Show webcam preview using Streamlit's native camera (compatibility function).""" st.info("Using Streamlit's native camera preview...") streamlit_camera_preview() def test_webcam_access() -> bool: """Test webcam access using Streamlit's native camera (compatibility function).""" return streamlit_camera_test() def find_available_camera() -> Optional[int]: """Find available camera (compatibility function - always returns 0 for Streamlit).""" # Streamlit handles camera selection automatically return 0 def get_webcam_error_message(camera_index: int) -> str: """Get helpful error message for webcam failures.""" return """ Camera access failed. Please check: - Browser camera permissions are granted - Camera is not being used by another application - Try refreshing the page - Use the 'Test Webcam' button for detailed diagnostics """