lucid-hf's picture
CI: deploy Docker/PDM Space
a65508e verified
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
"""