import gradio as gr import cv2 import numpy as np # Load the face detection model (using OpenCV's built-in classifier) # This is a fast, reliable model that works well for real-time applications. face_cascade = cv2.CascadeClassifier( cv2.data.haarcascades + 'haarcascade_frontalface_default.xml' ) def apply_zorro_mask(frame: np.ndarray) -> np.ndarray: """ This function is called for every frame from your webcam. It detects faces and draws a Zorro mask on them. """ if frame is None: return None # The frame from Gradio is in RGB, but OpenCV uses BGR. # Convert to BGR for processing, then back to RGB for display. frame_bgr = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR) # Convert the frame to grayscale, which is required for the face detector gray = cv2.cvtColor(frame_bgr, cv2.COLOR_BGR2GRAY) # Detect faces in the image # The parameters (scaleFactor, minNeighbors) can be tuned for better performance faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(60, 60)) # Loop over all detected faces and draw the mask for (x, y, w, h) in faces: # --- Draw the black Zorro mask (a rectangle over the eyes) --- mask_height = int(h * 0.4) # Make the mask cover the upper part of the face mask_y = y + int(h * 0.2) # Position it a bit below the top of the face cv2.rectangle(frame_bgr, (x, mask_y), (x + w, mask_y + mask_height), (0, 0, 0), -1) # -1 fills the rectangle # --- Create eye holes (two white circles) --- eye_y = mask_y + int(mask_height * 0.5) eye_radius = int(w * 0.1) # Left eye hole cv2.circle(frame_bgr, (x + int(w * 0.35), eye_y), eye_radius, (255, 255, 255), -1) # Right eye hole cv2.circle(frame_bgr, (x + int(w * 0.65), eye_y), eye_radius, (255, 255, 255), -1) # --- Optional: Draw a stylish "Z" mark on the mask --- cv2.putText(frame_bgr, "Z", (x + w - 30, y + h - 20), cv2.FONT_HERSHEY_SIMPLEX, 1.5, (0, 0, 255), 3) # Convert the frame back to RGB for Gradio to display frame_rgb = cv2.cvtColor(frame_bgr, cv2.COLOR_BGR2RGB) return frame_rgb # --- Build the Gradio Interface --- # The 'Blocks' API gives us more control than the simple 'Interface' API. with gr.Blocks(title="Real-Time Zorro Mask Sandbox") as demo: gr.Markdown("# 🎭 Real-Time Zorro Mask Sandbox") gr.Markdown("Allow webcam access. The mask will be applied to your face in real-time!") with gr.Row(): # Input: The live webcam stream. 'streaming=True' is crucial. input_webcam = gr.Image(sources=["webcam"], streaming=True, label="Your Webcam Feed") # Output: Where the processed video stream will be shown. output_video = gr.Image(label="Live Zorro Mask Output") # This is the magic line that creates the real-time loop. # It calls 'apply_zorro_mask' for every new frame from 'input_webcam' # and sends the result to 'output_video'. input_webcam.stream( fn=apply_zorro_mask, inputs=input_webcam, outputs=output_video, time_limit=10, # Optional: Stops the stream after 10 seconds if no new frames stream_every=0.05 # Optional: Controls the delay between frames (in seconds). Lower is faster. ) # Launch the app demo.launch()