kamcio1989's picture
Upload 8 files
c289710 verified
import gradio as gr
import numpy as np
from PIL import Image, ImageDraw
import json
from typing import Tuple, List, Dict, Any
import time
import threading
import queue
from models import load_detection_models, CV2_AVAILABLE # CV2_AVAILABLE needs to come from models.py
from utils import draw_detections, process_image, generate_tone, play_sound, AlarmSystem, AUDIO_AVAILABLE
# Global alarm system
alarm_system = AlarmSystem()
# Load models at startup
face_cascade, object_net, object_classes = load_detection_models()
def check_and_trigger_alarm(face_results, object_results, alarm_settings):
"""Check detection results and trigger alarm if conditions are met."""
if not alarm_settings.get("alarm_enabled", False):
return False, "Alarm disabled"
alarm_triggered = False
alarm_reason = ""
# Check face detection alarm
if alarm_settings.get("face_alarm", False) and face_results:
alarm_triggered = True
alarm_reason = f"Face detected ({len(face_results)} faces)"
# Check object detection alarm
elif alarm_settings.get("object_alarm", False) and object_results:
# Check for specific object types if specified
target_objects = alarm_settings.get("target_objects", [])
if target_objects:
detected_objects = [obj["label"] for obj in object_results if obj["label"] in target_objects]
if detected_objects:
alarm_triggered = True
alarm_reason = f"Target object detected: {', '.join(set(detected_objects))}"
else:
alarm_triggered = True
alarm_reason = f"Object detected ({len(object_results)} objects)"
# Trigger alarm if conditions are met
if alarm_triggered:
sound_type = alarm_settings.get("alarm_sound", "Beep")
if sound_type == "Custom":
sound_to_play = alarm_settings.get("custom_alarm_sound")
else:
sound_to_play = sound_type
if alarm_system.trigger_alarm(sound_to_play):
return True, f"🚨 ALARM TRIGGERED: {alarm_reason}"
else:
return False, "Alarm cooldown active"
return False, "No alarm conditions met"
def recognize_face_and_objects(
image: np.ndarray,
enable_face_detection: bool,
enable_object_detection: bool,
face_confidence: float,
object_confidence: float,
draw_boxes: bool,
show_labels: bool,
box_color: str,
alarm_enabled_val: bool, # New parameter for alarm_enabled
face_alarm_val: bool, # New parameter for face_alarm
object_alarm_val: bool, # New parameter for object_alarm
alarm_sound_val: str, # New parameter for alarm_sound
target_objects_val: List[str], # New parameter for target_objects
custom_alarm_sound_val: str
) -> Tuple[np.ndarray, str, str, str]:
"""
Perform face and object detection on the input image with alarm support.
"""
if image is None:
return None, "[]", "[]", "No image provided" # Changed this line to return empty JSON arrays for face and object results
# Convert PIL to numpy if needed
if isinstance(image, Image.Image):
image = np.array(image)
# Construct alarm_settings dictionary from the passed values
alarm_settings = {
"alarm_enabled": alarm_enabled_val,
"face_alarm": face_alarm_val,
"object_alarm": object_alarm_val,
"alarm_sound": alarm_sound_val,
"target_objects": target_objects_val,
"custom_alarm_sound": custom_alarm_sound_val
}
# Process image
processed_image, face_results, object_results = process_image(
image,
face_cascade,
object_net,
object_classes,
enable_face_detection,
enable_object_detection,
face_confidence,
object_confidence
)
# Check alarm conditions
alarm_status, alarm_message = check_and_trigger_alarm(face_results, object_results, alarm_settings)
# Draw detections if requested
if draw_boxes:
processed_image = draw_detections(
processed_image.copy(),
face_results,
object_results,
show_labels,
box_color
)
# Convert results to JSON
face_json = json.dumps(face_results, indent=2) if face_results else "[]"
object_json = json.dumps(object_results, indent=2) if object_results else "[]"
return processed_image, face_json, object_json, alarm_message
def webcam_recognition(
image: np.ndarray,
enable_face_detection: bool,
enable_object_detection: bool,
face_confidence: float,
object_confidence: float,
draw_boxes: bool,
show_labels: bool,
box_color: str,
alarm_enabled_val: bool, # New parameter for alarm_enabled
face_alarm_val: bool, # New parameter for face_alarm
object_alarm_val: bool, # New parameter for object_alarm
alarm_sound_val: str, # New parameter for alarm_sound
target_objects_val: List[str], # New parameter for target_objects
custom_alarm_sound_val: str
) -> np.ndarray:
"""Real-time webcam recognition with alarm."""
if image is None:
return None
# Construct alarm_settings dictionary from the passed values
alarm_settings = {
"alarm_enabled": alarm_enabled_val,
"face_alarm": face_alarm_val,
"object_alarm": object_alarm_val,
"alarm_sound": alarm_sound_val,
"target_objects": target_objects_val
}
processed_image, _, _, _ = recognize_face_and_objects(
image,
enable_face_detection,
enable_object_detection,
face_confidence,
object_confidence,
draw_boxes,
show_labels,
box_color,
alarm_enabled_val, # Pass these directly
face_alarm_val,
object_alarm_val,
alarm_sound_val,
target_objects_val,
custom_alarm_sound_val
)
return processed_image
def get_detection_statistics() -> str:
"""Get information about available detection models."""
if CV2_AVAILABLE:
stats = {
"face_detection": {
"model": "Haar Cascade (OpenCV)",
"features": ["Face detection", "Eye detection", "Smile detection"],
"speed": "Fast",
"accuracy": "Medium"
},
"object_detection": {
"model": "OpenCV DNN with MobileNet-SSD" if object_net else "Simulation Mode",
"classes": len(object_classes) if object_classes else 21,
"input_size": "300x300",
"speed": "Real-time capable" if object_net else "Simulation",
"accuracy": "High" if object_net else "Demo Mode"
}
}
else:
stats = {
"face_detection": {
"model": "PIL-based Simulation",
"features": ["Demo face detection"],
"speed": "Fast",
"accuracy": "Demo Mode",
"note": "Install OpenCV for real detection"
},
"object_detection": {
"model": "PIL-based Simulation",
"classes": 8,
"input_size": "Variable",
"speed": "Demo",
"accuracy": "Demo Mode",
"note": "Install OpenCV for real detection"
}
}
return json.dumps(stats, indent=2)
def test_alarm_sound(sound_type, custom_sound_file):
"""Test alarm sound."""
if not AUDIO_AVAILABLE:
return "⚠️ Audio not available. Install pyaudio for sound support."
try:
if sound_type == "Custom":
sound_to_play = custom_sound_file
if sound_to_play is None:
return "Custom sound selected, but no file uploaded."
else:
sound_to_play = sound_type
play_sound(sound_to_play)
# Give a more descriptive message for custom sounds
if sound_type == "Custom":
return f"βœ… Played custom sound"
else:
return f"βœ… Played {sound_type} sound"
except Exception as e:
return f"❌ Error playing sound: {str(e)}"
# Create custom CSS for better styling
custom_css = """
.main-container {
max-width: 1400px;
margin: 0 auto;
}
.settings-panel {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 10px;
padding: 20px;
}
.result-panel {
border: 2px solid #e0e0e0;
border-radius: 10px;
padding: 15px;
}
.image-container {
border: 1px solid #ddd;
border-radius: 8px;
overflow: hidden;
}
.warning-box {
background-color: #fff3cd;
border: 1px solid #ffeaa7;
border-radius: 8px;
padding: 15px;
margin-bottom: 20px;
}
.alarm-box {
background-color: #f8d7da;
border: 2px solid #f5c6cb;
border-radius: 8px;
padding: 15px;
margin-bottom: 20px;
animation: pulse 1s infinite;
}
@keyframes pulse {
0% { opacity: 1; }
50% { opacity: 0.7; }
100% { opacity: 1; }
}
"""
with gr.Blocks(title="Face & Object Recognition Platform") as demo:
gr.HTML(f"<style>{custom_css}</style>")
gr.Markdown("""
# πŸ” Face & Object Recognition Platform with Alarm System
Built with [anycoder](https://huggingface.co/spaces/akhaliq/anycoder)
Advanced computer vision platform for real-time face and object detection with customizable settings and alarm notifications.
""")
# Show warnings if dependencies are not available
if not CV2_AVAILABLE:
with gr.Row():
gr.Markdown("""
<div class="warning-box">
⚠️ **OpenCV Not Available**: Running in demonstration mode with simulated detections.
Install OpenCV (`pip install opencv-python`) for real face and object detection capabilities.
</div>
""")
if not AUDIO_AVAILABLE:
with gr.Row():
gr.Markdown("""
<div class="warning-box">
⚠️ **Audio Not Available**: Install audio libraries for alarm sounds: `pip install pyaudio`
</div>
""")
# Alarm state
alarm_status = gr.Textbox(label="Alarm Status", visible=False, interactive=False)
with gr.Row():
with gr.Column(scale=2):
gr.Markdown("### πŸ“€ Input Source")
with gr.Tabs():
with gr.TabItem("Upload Image"):
input_image = gr.Image(
label="Upload an image for analysis",
type="numpy",
height=400
)
analyze_btn = gr.Button("πŸ” Analyze Image", variant="primary", size="lg")
with gr.TabItem("Webcam"):
webcam_image = gr.Image(
label="Webcam Feed",
sources="webcam",
type="numpy",
streaming=True,
height=400
)
gr.Markdown("*Webcam provides real-time detection with alarm system*")
with gr.Column(scale=1):
gr.Markdown("### βš™οΈ Detection Settings")
with gr.Group(elem_classes=["settings-panel"]):
gr.Markdown("#### Detection Modes")
enable_face = gr.Checkbox(label="πŸ‘€ Enable Face Detection", value=True)
enable_objects = gr.Checkbox(label="πŸ“¦ Enable Object Detection", value=True)
gr.Markdown("#### Confidence Thresholds")
face_conf = gr.Slider(
label="Face Detection Confidence",
minimum=0.1,
maximum=1.0,
value=0.7,
step=0.1,
info="Lower values detect more faces"
)
object_conf = gr.Slider(
label="Object Detection Confidence",
minimum=0.1,
maximum=1.0,
value=0.5,
step=0.1,
info="Lower values detect more objects"
)
gr.Markdown("#### Display Options")
draw_boxes = gr.Checkbox(label="πŸ“ Draw Bounding Boxes", value=True)
show_labels = gr.Checkbox(label="🏷️ Show Labels", value=True)
box_color = gr.Dropdown(
label="Box Color",
choices=["red", "green", "blue", "yellow", "purple", "orange"],
value="red"
)
with gr.Row():
with gr.Column():
gr.Markdown("### πŸ–ΌοΈ Detection Results")
output_image = gr.Image(
label="Processed Image with Detections",
type="numpy",
height=400,
elem_classes=["image-container"]
)
# Alarm status display
alarm_display = gr.Textbox(
label="🚨 Alarm Status",
value="Ready",
interactive=False,
elem_classes=["alarm-box" if False else ""]
)
with gr.Column():
with gr.Tabs():
with gr.TabItem("πŸ‘€ Face Results"):
face_results = gr.JSON(
label="Face Detection Data",
elem_classes=["result-panel"]
)
with gr.TabItem("πŸ“¦ Object Results"):
object_results = gr.JSON(
label="Object Detection Data",
elem_classes=["result-panel"]
)
with gr.TabItem("🚨 Alarm Settings"):
gr.Markdown("#### Configure Alarm System")
alarm_enabled = gr.Checkbox(label="πŸ”” Enable Alarm System", value=False)
face_alarm = gr.Checkbox(label="πŸ‘€ Alarm on Face Detection", value=True)
object_alarm = gr.Checkbox(label="πŸ“¦ Alarm on Object Detection", value=True)
alarm_sound = gr.Dropdown(
label="πŸ”Š Alarm Sound",
choices=["Beep", "Siren", "Chime", "Alert", "Buzzer", "Ring", "Custom"],
value="Beep",
info="Select alarm sound type"
)
custom_alarm_sound = gr.File(
label="Upload Custom Alarm Sound (.wav)",
file_types=[".wav"],
visible=False
)
def toggle_custom_sound(sound_choice):
return gr.update(visible=sound_choice == "Custom")
alarm_sound.change(
fn=toggle_custom_sound,
inputs=alarm_sound,
outputs=custom_alarm_sound
)
target_objects = gr.CheckboxGroup(
label="🎯 Specific Objects to Trigger Alarm (optional)",
choices=["person", "car", "dog", "cat", "bottle", "chair", "laptop", "phone"],
info="Leave empty to alarm on any object"
)
test_sound_btn = gr.Button("πŸ”Š Test Sound", variant="secondary")
sound_test_result = gr.Textbox(label="Sound Test Result", interactive=False)
with gr.TabItem("ℹ️ Model Info"):
model_info = gr.JSON(
label="Detection Models Information",
value=json.loads(get_detection_statistics()),
elem_classes=["result-panel"]
)
# Event handlers
# NOTE: The gr.State values are captured at the time the UI is created.
# To get the current values, we need to pass the Gradio components themselves
# and then read their values in the `recognize_face_and_objects` function.
analyze_btn.click(
fn=recognize_face_and_objects,
inputs=[
input_image,
enable_face,
enable_objects,
face_conf,
object_conf,
draw_boxes,
show_labels,
box_color,
# Pass the Gradio components, not their values
alarm_enabled,
face_alarm,
object_alarm,
alarm_sound,
target_objects,
custom_alarm_sound
],
outputs=[output_image, face_results, object_results, alarm_display]
)
# Real-time webcam processing
webcam_image.stream(
fn=webcam_recognition,
inputs=[
webcam_image,
enable_face,
enable_objects,
face_conf,
object_conf,
draw_boxes,
show_labels,
box_color,
# Pass the Gradio components, not their values
alarm_enabled,
face_alarm,
object_alarm,
alarm_sound,
target_objects,
custom_alarm_sound
],
outputs=[output_image],
time_limit=30,
stream_every=0.5
)
# Test sound button
test_sound_btn.click(
fn=test_alarm_sound,
inputs=[alarm_sound, custom_alarm_sound],
outputs=[sound_test_result]
)
gr.Markdown("""
---
### πŸ“š Usage Instructions
1. **Upload Image**: Select an image from your device for analysis
2. **Webcam**: Use your webcam for real-time detection with alarms
3. **Adjust Settings**: Customize confidence thresholds and display options
4. **Configure Alarm**: Set up alarm conditions and sounds in the Alarm Settings tab
5. **View Results**: See detections overlayed on the image with detailed JSON data
### 🚨 Alarm Features
- **Face Detection Alarm**: Triggers when faces are detected
- **Object Detection Alarm**: Triggers when objects are detected (all or specific types)
- **Multiple Sounds**: Choose from 6 different alarm sounds
- **Cooldown Period**: Prevents alarm spam (2-second cooldown)
- **Real-time Monitoring**: Works with webcam for continuous monitoring
### 🎯 Features
- **Face Detection**: Identifies faces in images using Haar Cascade classifiers (or simulation mode)
- **Object Detection**: Recognizes object classes using MobileNet-SSD (or simulation mode)
- **Real-time Processing**: Webcam support with live detection and alarms
- **Customizable**: Adjustable confidence thresholds and visual settings
- **Detailed Output**: JSON formatted results with coordinates and confidence scores
### βš™οΈ Installation Notes
- Install OpenCV for full functionality: `pip install opencv-python`
- Install audio support for alarms: `pip install pyaudio`
""")
if __name__ == "__main__":
demo.launch(share=True, debug=True)