Spaces:
Running
Running
import av | |
import cv2 | |
import numpy as np | |
import streamlit as st | |
import os | |
import time | |
from streamlit_webrtc import webrtc_streamer, WebRtcMode, VideoHTMLAttributes | |
from src.opencv_utils import OpenCVUtils | |
from twilio.rest import Client | |
# Custom theme settings | |
st.set_page_config( | |
page_title="OpenCV Explorer", | |
page_icon="⚫", # Changed icon for minimalism | |
layout="wide", | |
initial_sidebar_state="expanded", | |
) | |
# Create a custom theme | |
def create_custom_theme(): | |
# Create a .streamlit directory if it doesn't exist | |
os.makedirs(".streamlit", exist_ok=True) | |
# Create a config.toml file with custom theme settings | |
with open(".streamlit/config.toml", "w") as f: | |
f.write( | |
""" | |
[theme] | |
base = "dark" # Use Streamlit's dark theme as a base | |
primaryColor = "#CCCCCC" # Light Grey accent | |
backgroundColor = "#0E1117" # Default Streamlit dark bg | |
secondaryBackgroundColor = "#262730" # Slightly lighter dark grey | |
textColor = "#FAFAFA" # Light text | |
font = "sans serif" | |
""" | |
) | |
# Apply custom theme | |
create_custom_theme() | |
def get_ice_servers(): | |
""" | |
Get ICE servers configuration. | |
For Streamlit Cloud deployment, a TURN server is required in addition to STUN. | |
This function will try to use Twilio's TURN server service if credentials are available, | |
otherwise it falls back to a free STUN server from Google. | |
""" | |
try: | |
# Try to get Twilio credentials from environment variables | |
account_sid = os.environ.get("TWILIO_ACCOUNT_SID") | |
auth_token = os.environ.get("TWILIO_AUTH_TOKEN") | |
if account_sid and auth_token: | |
client = Client(account_sid, auth_token) | |
token = client.tokens.create() | |
return token.ice_servers | |
else: | |
st.warning( | |
"Twilio credentials not found. Using free STUN server only, which may not work reliably." # Removed Streamlit Cloud mention for generality | |
) | |
except Exception as e: | |
st.error(f"Error setting up Twilio TURN servers: {e}") | |
# Fallback to Google's free STUN server | |
return [{"urls": ["stun:stun.l.google.com:19302"]}] | |
def get_app(): | |
return OpenCVUtils() | |
app = get_app() | |
# --- HIDE STREAMLIT STYLE --- | |
hide_st_style = """ | |
<style> | |
#MainMenu {visibility: hidden;} | |
footer {visibility: hidden;} | |
header {visibility: hidden;} | |
/* Body background - Already set by theme config */ | |
/* .stApp { | |
background-color: #0E1117; | |
} */ | |
/* Tab styling */ | |
.stTabs [data-baseweb="tab-list"] { | |
gap: 8px; /* Slightly reduced gap */ | |
border-bottom: 1px solid #333333; /* Darker border */ | |
} | |
.stTabs [data-baseweb="tab"] { | |
background-color: transparent; /* Make tabs transparent */ | |
border-radius: 0; /* Remove border radius */ | |
padding: 10px 15px; | |
color: #AAAAAA; /* Lighter Grey text */ | |
border-bottom: 2px solid transparent; /* Prepare for selected indicator */ | |
transition: all 0.3s ease; | |
} | |
.stTabs [data-baseweb="tab"]:hover { | |
background-color: #262730; /* Dark grey hover */ | |
color: #FAFAFA; /* White text on hover */ | |
} | |
.stTabs [aria-selected="true"] { | |
background-color: transparent !important; | |
color: #FAFAFA !important; /* White text for selected */ | |
border-bottom: 2px solid #CCCCCC !important; /* Light grey underline for selected */ | |
font-weight: 600; /* Make selected tab bold */ | |
} | |
/* Sidebar styling - Mostly handled by theme config */ | |
/* .css-1d391kg { | |
background-color: #262730 !important; | |
} */ | |
/* Ensure sidebar text is readable - Mostly handled by theme config */ | |
/* .css-1d391kg .stMarkdown, .css-1d391kg .stCheckbox, .css-1d391kg .stExpander, .css-1d391kg .stText, .css-1d391kg .stButton > button { | |
color: #FAFAFA !important; | |
} */ | |
/* Button styling */ | |
.stButton>button { | |
background-color: #262730 !important; /* Dark grey background */ | |
color: #FAFAFA !important; /* Light text */ | |
border: 1px solid #444444 !important; /* Slightly lighter border */ | |
transition: all 0.3s ease !important; | |
box-shadow: none !important; /* Remove default shadow */ | |
} | |
.stButton>button:hover { | |
background-color: #3a3c44 !important; /* Lighter grey on hover */ | |
border-color: #666666 !important; | |
transform: none !important; /* Remove hover transform */ | |
box-shadow: none !important; | |
} | |
.stButton>button:active { | |
background-color: #444444 !important; /* Slightly darker grey on click */ | |
} | |
/* Expander header styling */ | |
.stExpander > div:first-child { | |
background-color: #262730; /* Dark grey background for expander header */ | |
border-radius: 4px; | |
} | |
.stExpander header { /* Target expander header specifically */ | |
color: #FAFAFA !important; /* Light text for expander header */ | |
font-weight: 600; | |
} | |
/* General adjustments for minimalist feel */ | |
h1, h2, h3, h4, h5, h6 { | |
color: #FAFAFA; /* Ensure headers are light */ | |
} | |
.stMarkdown p { | |
color: #CCCCCC; /* Slightly darker light color for paragraph text */ | |
} | |
/* Color Preview Text */ | |
.color-preview-text { | |
color: #1E1E1E !important; /* Ensure text is visible on light/dark previews */ | |
text-shadow: 0 0 2px #FFFFFF; /* Add a subtle white shadow for contrast */ | |
} | |
</style> | |
""" | |
st.markdown(hide_st_style, unsafe_allow_html=True) | |
# --------------------------- | |
# Top header with logo and title | |
col1, col2 = st.columns([1, 5]) | |
with col1: | |
st.image( | |
"https://opencv.org/wp-content/uploads/2020/07/OpenCV_logo_black-2.png", | |
width=100, | |
) | |
with col2: | |
st.title("OpenCV Explorer") | |
st.markdown( | |
""" | |
<p style='font-size: 18px; margin-top: -10px;'> | |
Explore computer vision filters and transformations in real-time using your webcam. | |
</p> | |
""", | |
unsafe_allow_html=True, | |
) | |
# Create main layout | |
main_tabs = st.tabs(["📹 Camera Feed", "ℹ️ About", "📋 Documentation"]) | |
with main_tabs[0]: # Camera Feed Tab | |
# Create columns for camera and controls | |
video_col, control_col = st.columns([3, 1]) | |
with control_col: | |
st.markdown("## 🎛️ Controls") | |
# Organize filters into categories | |
filter_categories = { | |
"Basic Transformations": ["Resize", "Rotation", "Blur", "Sharpen"], | |
"Edge & Contour Detection": ["Canny", "Contour", "Hough Lines"], | |
"Color Operations": [ | |
"Color Filter", | |
"Histogram Equalization", | |
"Color Quantization", | |
], | |
"Artistic Effects": ["Pencil Sketch", "Morphology", "Adaptive Threshold"], | |
"Advanced Features": ["Optical Flow", "Hand Tracker", "Face Tracker"], | |
} | |
# Use a dictionary to store the expanded state of each category | |
if "expanded" not in st.session_state: | |
st.session_state.expanded = {cat: False for cat in filter_categories} | |
st.session_state.expanded["Basic Transformations"] = ( | |
True # Expand the first one by default | |
) | |
# Create filter selection UI with categories | |
selected_functions = [] | |
for category, filters in filter_categories.items(): | |
with st.expander( | |
f"**{category}**", expanded=st.session_state.expanded[category] | |
): | |
# Show checkboxes for each filter in this category | |
selected_in_category = [] | |
for filter_name in filters: | |
if st.checkbox(filter_name, key=f"check_{filter_name}"): | |
selected_in_category.append(filter_name) | |
# If any filters selected in this category, add a reorder section | |
if selected_in_category: | |
st.markdown("**Order within category:**") | |
for i, filter_name in enumerate(selected_in_category): | |
col1, col2 = st.columns([4, 1]) | |
with col1: | |
st.text(f"{i+1}. {filter_name}") | |
with col2: | |
if i > 0 and st.button("↑", key=f"up_{filter_name}"): | |
# Move filter up in the list | |
selected_in_category[i], selected_in_category[i - 1] = ( | |
selected_in_category[i - 1], | |
selected_in_category[i], | |
) | |
st.rerun() | |
# Add selected filters to the main list | |
selected_functions.extend(selected_in_category) | |
# Show the currently applied filters | |
if selected_functions: | |
st.markdown("### 📌 Applied Filters") | |
for i, fn in enumerate(selected_functions): | |
st.markdown(f"**{i+1}.** {fn}") | |
else: | |
st.info("Select filters to apply to the camera feed") | |
# Filter parameters - using expanders for cleaner UI | |
if any(f in selected_functions for f in ["Resize"]): | |
with st.expander("📐 Resize Parameters", expanded=True): | |
w = st.slider("Width", 320, 1280, 640) | |
h = st.slider("Height", 240, 720, 480) | |
else: | |
# Default values if not displayed | |
w, h = 640, 480 | |
if "Rotation" in selected_functions: | |
with st.expander("🔄 Rotation Parameters", expanded=True): | |
ang = st.slider("Angle", 0, 360, 0) | |
else: | |
ang = 0 | |
if "Blur" in selected_functions: | |
with st.expander("🌫️ Blur Parameters", expanded=True): | |
bk = st.slider("Kernel Size (odd)", 1, 15, 5, step=2) | |
else: | |
bk = 5 | |
if "Color Filter" in selected_functions: | |
with st.expander("🎨 Color Filter Parameters", expanded=True): | |
col1, col2 = st.columns(2) | |
with col1: | |
st.markdown("**Lower Bounds**") | |
lh = st.slider("Hue (L)", 0, 180, 0) | |
ls = st.slider("Sat (L)", 0, 255, 0) | |
lv = st.slider("Val (L)", 0, 255, 0) | |
with col2: | |
st.markdown("**Upper Bounds**") | |
uh = st.slider("Hue (U)", 0, 180, 180) | |
us = st.slider("Sat (U)", 0, 255, 255) | |
uv = st.slider("Val (U)", 0, 255, 255) | |
# Color preview - Make it dynamic again | |
# Use the lower bound HSV values to generate an HSL color for CSS | |
preview_color_hsl = f"hsl({lh * 2}, {ls / 2.55}%, {lv / 2.55}%)" | |
st.markdown( | |
f""" | |
<div style="background-color: {preview_color_hsl}; width: 100%; height: 30px; | |
border: 1px solid #555555; border-radius: 5px; margin-top: 10px;"> | |
<p class='color-preview-text' style='text-align: center; line-height: 30px; font-size: 12px; font-weight: bold;'> | |
Preview (Lower Bound) | |
</p> | |
</div> | |
""", | |
unsafe_allow_html=True, | |
) | |
else: | |
lh, ls, lv, uh, us, uv = 0, 0, 0, 180, 255, 255 | |
if "Canny" in selected_functions: | |
with st.expander("📊 Canny Edge Parameters", expanded=True): | |
lc = st.slider("Lower Threshold", 0, 255, 100) | |
uc = st.slider("Upper Threshold", 0, 255, 200) | |
else: | |
lc, uc = 100, 200 | |
if "Morphology" in selected_functions: | |
with st.expander("🧩 Morphology Parameters", expanded=True): | |
morph_op = st.selectbox( | |
"Operation", ["erode", "dilate", "open", "close"] | |
) | |
morph_ks = st.slider("Kernel Size", 1, 31, 5, step=2) | |
else: | |
morph_op, morph_ks = "erode", 5 | |
with video_col: | |
st.markdown("## 📹 Live Camera Feed") | |
# WebRTC settings for real-time video | |
prev_gray = None | |
def video_frame_callback(frame: av.VideoFrame) -> av.VideoFrame: | |
global prev_gray | |
img = frame.to_ndarray(format="bgr24") | |
curr_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) | |
for fn in selected_functions: | |
if fn == "Color Filter": | |
img = app.apply_color_filter(img, (lh, ls, lv), (uh, us, uv)) | |
elif fn == "Canny": | |
img = app.apply_edge_detection(img, lc, uc) | |
elif fn == "Blur": | |
img = app.blur_image(img, bk) | |
elif fn == "Rotation": | |
img = app.rotate_image(img, ang) | |
elif fn == "Resize": | |
img = app.resize_image(img, w, h) | |
elif fn == "Contour": | |
img = app.apply_contour_detection(img) | |
elif fn == "Histogram Equalization": | |
img = app.equalize_histogram(img) | |
elif fn == "Adaptive Threshold": | |
img = app.adaptive_threshold(img) | |
elif fn == "Morphology": | |
img = app.morphology(img, morph_op, morph_ks) | |
elif fn == "Sharpen": | |
img = app.sharpen(img) | |
elif fn == "Hough Lines": | |
img = app.hough_lines(img) | |
elif fn == "Optical Flow" and prev_gray is not None: | |
img = app.optical_flow(prev_gray, curr_gray, img) | |
elif fn == "Pencil Sketch": | |
img = app.pencil_sketch(img) | |
elif fn == "Color Quantization": | |
img = app.color_quantization(img) | |
elif fn == "Hand Tracker": | |
img = app.detect_hands(img) | |
elif fn == "Face Tracker": | |
img = app.detect_faces(img) | |
prev_gray = curr_gray | |
return av.VideoFrame.from_ndarray(img, format="bgr24") | |
webrtc_streamer( | |
key="opencv-explorer", | |
mode=WebRtcMode.SENDRECV, | |
rtc_configuration={"iceServers": get_ice_servers()}, | |
video_frame_callback=video_frame_callback, | |
media_stream_constraints={"video": True, "audio": False}, | |
async_processing=True, | |
video_html_attrs=VideoHTMLAttributes( | |
autoPlay=True, | |
controls=False, | |
style={ | |
"width": f"{w}px", | |
"height": f"{h}px", | |
"border-radius": "8px", | |
"margin": "0 auto", | |
"display": "block", | |
"border": "2px solid #AAAAAA", # Changed border to lighter grey | |
}, | |
), | |
) | |
# Performance metrics | |
with st.expander("📊 Performance Metrics", expanded=False): | |
col1, col2, col3 = st.columns(3) | |
col1.metric("Resolution", f"{w}x{h} px") | |
col2.metric("Filters Applied", len(selected_functions)) | |
col3.metric("Frame Processing", f"{time.time():.2f} ms", delta=None) | |
with main_tabs[1]: # About Tab | |
st.markdown( | |
""" | |
## About OpenCV Explorer | |
OpenCV Explorer is an interactive web application that allows you to experiment with various computer vision techniques in real-time using your webcam. This application is built with: | |
- **OpenCV**: Open Source Computer Vision Library | |
- **Streamlit**: An open-source app framework for Machine Learning and Data Science | |
- **WebRTC**: Web Real-Time Communication for live video streaming | |
### Features | |
- Apply multiple filters and transformations to your webcam feed | |
- Adjust parameters in real-time | |
- Experiment with advanced computer vision techniques | |
- Learn about image processing concepts | |
### How to Use | |
1. Select one or more filters from the categories in the control panel | |
2. Adjust the parameters for each selected filter | |
3. See the results in real-time through your webcam | |
4. Reorder filters to create different effects | |
### Privacy Note | |
All processing is done in your browser. No video data is sent to any server except for the WebRTC connection. | |
""" | |
) | |
with main_tabs[2]: # Documentation Tab | |
st.markdown( | |
""" | |
## Documentation | |
This section provides details about the available computer vision filters and transformations. | |
You can select multiple filters, and they will be applied sequentially in the order chosen within each category. | |
Adjust the parameters in the control panel to see the effects in real-time. | |
### Available Filters | |
""" | |
) | |
# Create documentation for each filter category | |
for category, filters in filter_categories.items(): | |
with st.expander(f"**{category}**", expanded=False): | |
for filter_name in filters: | |
st.markdown(f"#### {filter_name}") | |
# Add detailed description and links for each filter | |
if filter_name == "Resize": | |
st.markdown( | |
""" | |
Changes the dimensions (width and height) of the video frame. Useful for adjusting the output size or preparing the frame for other operations that require a specific input size. | |
**Parameters:** | |
- **Width**: Target width in pixels. | |
- **Height**: Target height in pixels. | |
**Usage**: Scaling for performance, UI fitting, preprocessing for models. | |
**Docs**: [OpenCV Geometric Transformations](https://docs.opencv.org/4.x/da/d6e/tutorial_py_geometric_transformations.html) (See `cv2.resize`) | |
""" | |
) | |
elif filter_name == "Rotation": | |
st.markdown( | |
""" | |
Rotates the video frame around its center by a specified angle. | |
**Parameters:** | |
- **Angle**: Rotation angle in degrees (0-360). | |
**Usage**: Image orientation correction, creative effects. | |
**Docs**: [OpenCV Geometric Transformations](https://docs.opencv.org/4.x/da/d6e/tutorial_py_geometric_transformations.html) (See `cv2.getRotationMatrix2D` and `cv2.warpAffine`) | |
""" | |
) | |
elif filter_name == "Blur": | |
st.markdown( | |
""" | |
Applies Gaussian blur to smooth the image, reducing noise and detail. The kernel size determines the extent of blurring. | |
**Parameters:** | |
- **Kernel Size**: Size of the blurring matrix (must be an odd number). Higher values create more blur. | |
**Usage**: Noise reduction, detail smoothing, pre-processing for edge detection or other algorithms. | |
**Docs**: [OpenCV Smoothing Images](https://docs.opencv.org/4.x/d4/d13/tutorial_py_filtering.html) (See `cv2.GaussianBlur`) | |
""" | |
) | |
elif filter_name == "Sharpen": | |
st.markdown( | |
""" | |
Enhances the edges and details in the image using a sharpening kernel. This is achieved by subtracting a blurred version of the image from the original. | |
**Parameters:** None (uses a fixed kernel). | |
**Usage**: Enhancing image clarity, highlighting details. | |
**Docs**: [OpenCV Image Filtering Concepts](https://docs.opencv.org/4.x/d4/d13/tutorial_py_filtering.html) (Concept explanation, the implementation uses a custom kernel) | |
""" | |
) | |
elif filter_name == "Canny": | |
st.markdown( | |
""" | |
Detects edges in the image using the Canny edge detection algorithm, a multi-stage process to find sharp changes in intensity. | |
**Parameters:** | |
- **Lower Threshold**: Minimum intensity gradient to be considered a potential edge. | |
- **Upper Threshold**: Maximum intensity gradient. Edges above this are definite edges. Pixels between the thresholds are included if connected to definite edges. | |
**Usage**: Edge detection, feature extraction, object boundary identification. | |
**Docs**: [OpenCV Canny Edge Detection](https://docs.opencv.org/4.x/da/d22/tutorial_py_canny.html) | |
""" | |
) | |
elif filter_name == "Contour": | |
st.markdown( | |
""" | |
Finds and draws contours (continuous curves joining points along a boundary with the same intensity) in the image. Usually applied after thresholding or edge detection. | |
**Parameters:** None (finds contours on the processed image and draws them). | |
**Usage**: Object detection, shape analysis, feature extraction. | |
**Docs**: [OpenCV Contours](https://docs.opencv.org/4.x/d4/d73/tutorial_py_contours_begin.html) (See `cv2.findContours`, `cv2.drawContours`) | |
""" | |
) | |
elif filter_name == "Hough Lines": | |
st.markdown( | |
""" | |
Detects straight lines in the image using the Hough Line Transform (Probabilistic variant). Works best on edge-detected images. | |
**Parameters:** None (uses preset parameters for `cv2.HoughLinesP`). | |
**Usage**: Line detection in images, structure identification. | |
**Docs**: [OpenCV Hough Line Transform](https://docs.opencv.org/4.x/d6/d10/tutorial_py_houghlines.html) (See `cv2.HoughLinesP`) | |
""" | |
) | |
elif filter_name == "Color Filter": | |
st.markdown( | |
""" | |
Isolates specific colors by converting the image to HSV (Hue, Saturation, Value) color space and applying a threshold based on the selected ranges. | |
**Parameters:** | |
- **Lower Bounds (Hue, Sat, Val)**: Minimum HSV values for the color range. | |
- **Upper Bounds (Hue, Sat, Val)**: Maximum HSV values for the color range. | |
**Usage**: Object detection based on color, color segmentation, special effects. | |
**Docs**: [OpenCV Changing Colorspaces](https://docs.opencv.org/4.x/df/d9d/tutorial_py_colorspaces.html) (See `cv2.cvtColor` and `cv2.inRange`) | |
""" | |
) | |
elif filter_name == "Histogram Equalization": | |
st.markdown( | |
""" | |
Improves contrast in grayscale images by redistributing pixel intensities more evenly across the histogram. Applied to the Value channel if the input is color. | |
**Parameters:** None. | |
**Usage**: Enhancing contrast in low-contrast images, improving visibility of details. | |
**Docs**: [OpenCV Histogram Equalization](https://docs.opencv.org/4.x/d5/daf/tutorial_py_histogram_equalization.html) (See `cv2.equalizeHist`) | |
""" | |
) | |
elif filter_name == "Color Quantization": | |
st.markdown( | |
""" | |
Reduces the number of distinct colors in an image using K-Means clustering in the color space. Groups similar colors together. | |
**Parameters:** None (uses a fixed number of clusters, K=8). | |
**Usage**: Image compression, posterization effect, simplifying color palettes. | |
**Docs**: [OpenCV K-Means Clustering](https://docs.opencv.org/4.x/d1/d5c/tutorial_py_kmeans_opencv.html) (Underlying algorithm) | |
""" | |
) | |
elif filter_name == "Pencil Sketch": | |
st.markdown( | |
""" | |
Creates a pencil sketch effect by converting the image to grayscale, inverting it, blurring the inverted image, and blending it with the original grayscale image using color dodge. | |
**Parameters:** None. | |
**Usage**: Artistic image transformation, creating sketch-like visuals. | |
**Docs**: Involves multiple OpenCV steps (Grayscale, Blur, Blending). See [Color Dodge Blending](https://en.wikipedia.org/wiki/Blend_modes#Dodge_and_burn). | |
""" | |
) | |
elif filter_name == "Morphology": | |
st.markdown( | |
""" | |
Applies morphological operations (Erode, Dilate, Open, Close) to modify the shape of features in the image, typically on binary images. | |
**Parameters:** | |
- **Operation**: Type of morphological operation (`erode`, `dilate`, `open`, `close`). | |
- **Kernel Size**: Size of the structuring element used (odd number). | |
**Usage**: Noise removal, joining broken parts, thinning/thickening features. | |
**Docs**: [OpenCV Morphological Transformations](https://docs.opencv.org/4.x/d9/d61/tutorial_py_morphological_ops.html) (See `cv2.erode`, `cv2.dilate`, `cv2.morphologyEx`) | |
""" | |
) | |
elif filter_name == "Adaptive Threshold": | |
st.markdown( | |
""" | |
Applies adaptive thresholding, where the threshold value is calculated locally for different regions of the image. Useful for images with varying illumination. | |
**Parameters:** None (uses `cv2.ADAPTIVE_THRESH_GAUSSIAN_C`). | |
**Usage**: Image segmentation in non-uniform lighting conditions. | |
**Docs**: [OpenCV Image Thresholding](https://docs.opencv.org/4.x/d7/d4d/tutorial_py_thresholding.html) (See `cv2.adaptiveThreshold`) | |
""" | |
) | |
elif filter_name == "Optical Flow": | |
st.markdown( | |
""" | |
Calculates and visualizes the apparent motion of objects between consecutive frames using the Farneback algorithm. Shows motion vectors as lines on the image. | |
**Parameters:** None (Requires previous frame data internally). | |
**Usage**: Motion tracking, video stabilization analysis, action recognition. | |
**Docs**: [OpenCV Optical Flow](https://docs.opencv.org/4.x/d4/dee/tutorial_optical_flow.html) (See `cv2.calcOpticalFlowFarneback`) | |
""" | |
) | |
elif filter_name == "Hand Tracker": | |
st.markdown( | |
""" | |
Detects and tracks hand positions and landmarks (joints) in real-time using the MediaPipe Hands solution. Draws landmarks and connections on the detected hands. | |
**Parameters:** None (uses pre-trained MediaPipe models). | |
**Usage**: Gesture recognition, sign language interpretation, virtual object interaction, hand pose estimation. | |
**Docs**: [MediaPipe Hand Landmarker](https://developers.google.com/mediapipe/solutions/vision/hand_landmarker) | |
""" | |
) | |
elif filter_name == "Face Tracker": | |
st.markdown( | |
""" | |
Detects faces in the video feed using the MediaPipe Face Detection solution and draws bounding boxes around them. | |
**Parameters:** None (uses pre-trained MediaPipe models). | |
**Usage**: Face detection, counting people, basic facial analysis applications, input for face recognition or landmark detection. | |
**Docs**: [MediaPipe Face Detector](https://developers.google.com/mediapipe/solutions/vision/face_detector) | |
""" | |
) | |
else: | |
# Fallback for any filters missed | |
st.markdown( | |
f"Detailed documentation for the **{filter_name}** filter is pending." | |
) | |
st.divider() # Add a separator between filter descriptions | |
st.markdown( | |
""" | |
### General Technical Details | |
- **OpenCV**: The core library used for most image processing functions. [OpenCV Python Tutorials](https://docs.opencv.org/4.x/d6/d00/tutorial_py_root.html) | |
- **MediaPipe**: Used for the advanced Hand and Face Tracking features. [MediaPipe Solutions](https://developers.google.com/mediapipe/solutions/) | |
- **Streamlit**: The framework used to build this web application interface. [Streamlit Documentation](https://docs.streamlit.io/) | |
- **WebRTC**: Enables real-time video streaming from your webcam to the browser for processing. (Handled by `streamlit-webrtc`) | |
""" | |
) | |
st.markdown( | |
""" | |
<div style="position: fixed; bottom: 0; width: 100%; background-color: #0E1117; | |
padding: 8px; text-align: center; border-top: 1px solid #262730;"> | |
<p style="margin: 0; font-size: 13px; color: #AAAAAA;"> | |
OpenCV Explorer | Built with Streamlit | |
</p> | |
</div> | |
""", | |
unsafe_allow_html=True, | |
) | |