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"") 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("""
âš ī¸ **OpenCV Not Available**: Running in demonstration mode with simulated detections. Install OpenCV (`pip install opencv-python`) for real face and object detection capabilities.
""") if not AUDIO_AVAILABLE: with gr.Row(): gr.Markdown("""
âš ī¸ **Audio Not Available**: Install audio libraries for alarm sounds: `pip install pyaudio`
""") # 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)