Spaces:
Running
Running
File size: 4,148 Bytes
71c1ed1 91d7a92 71c1ed1 91d7a92 71c1ed1 91d7a92 71c1ed1 31cd5f1 5a38d5b 71c1ed1 5a38d5b 91d7a92 71c1ed1 91d7a92 71c1ed1 9c42577 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | import gradio as gr
import cv2
import numpy as np
from model import EmotionPredictor
# Initialize the predictor
predictor = EmotionPredictor()
# Load Haar Cascade for face detection
face_cascade = cv2.CascadeClassifier(
cv2.data.haarcascades + "haarcascade_frontalface_default.xml"
)
if face_cascade.empty():
raise RuntimeError("Failed to load Haar Cascade")
def predict_emotion(image):
"""
Predict emotion from an image.
Args:
image: PIL Image or numpy array
Returns:
annotated image and emotion prediction
"""
if image is None:
return None, "No image provided"
# Convert PIL Image to numpy array if needed
if isinstance(image, np.ndarray):
frame = image
else:
frame = np.array(image)
# Convert RGB to BGR for OpenCV
if len(frame.shape) == 3 and frame.shape[2] == 3:
frame_bgr = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
else:
frame_bgr = frame
# Convert to grayscale for face detection
gray = cv2.cvtColor(frame_bgr, cv2.COLOR_BGR2GRAY)
# Detect faces
detected = face_cascade.detectMultiScale(
gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30)
)
if len(detected) == 0:
return frame, "No face detected"
# Get the largest face
faces = [max(detected, key=lambda r: r[2]*r[3])]
# Process the face
output_frame = frame_bgr.copy()
emotions = []
for (x, y, w, h) in faces:
# Extract face region
face_rgb = cv2.cvtColor(frame_bgr[y:y+h, x:x+w], cv2.COLOR_BGR2RGB)
# Predict emotion
emotion = predictor.predict(face_rgb)
emotions.append(emotion)
# Draw rectangle and label
cv2.rectangle(output_frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
cv2.putText(
output_frame, emotion, (x, y - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2
)
# Convert back to RGB for display
output_frame_rgb = cv2.cvtColor(output_frame, cv2.COLOR_BGR2RGB)
# Return annotated image and detected emotion
emotion_text = ", ".join(emotions) if emotions else "No emotion detected"
return output_frame_rgb, f"Detected emotion(s): {emotion_text}"
# Create Gradio interface
with gr.Blocks(title="Smilo😃 - Real-Time Emotion Detection") as demo:
gr.HTML("""
<div style="background: linear-gradient(90deg, #FF9933 0%, #D0B264 50%, #469F93 100%);
padding: 40px;
border-radius: 12px;
text-align: center;
color: white;
font-family: 'Helvetica Neue', Arial, sans-serif;
margin-bottom: 20px;">
<h1 style="color: white; margin: 0; margin-bottom: 10px; font-weight: 900; font-size: 3.5em; display: flex; align-items: center; justify-content: center; gap: 10px;">
Smilo <span style="font-size: 0.9em;">😃</span>
</h1>
<p style="color: #f0f0f0; font-size: 1.2em; margin: 0; font-weight: 400; letter-spacing: 0.5px;">Real-Time Emotion Detection powered by PyTorch & OpenCV <a href='https://github.com/TejeshNaiduKona/Smilo' target='_blank'>GitHub</a></p>
</div>
""")
with gr.Row():
with gr.Column():
image_input = gr.Image(
label="Input Image",
type="pil",
sources=["upload", "webcam"]
)
submit_btn = gr.Button("Predict Emotion", variant="primary")
with gr.Column():
image_output = gr.Image(label="Annotated Image")
emotion_output = gr.Textbox(label="Prediction Result", interactive=False)
# Connect the function to the button
submit_btn.click(
fn=predict_emotion,
inputs=[image_input],
outputs=[image_output, emotion_output]
)
# Also run prediction when image is uploaded
image_input.change(
fn=predict_emotion,
inputs=[image_input],
outputs=[image_output, emotion_output]
)
if __name__ == "__main__":
demo.launch() |