face_emotion / app.py
JasonKishore's picture
Create app.py
a844511 verified
Raw
History Blame Contribute Delete
2.92 kB
import cv2
import numpy as np
import gradio as gr
from fer import FER
# FER expects RGB images; OpenCV frames are BGR. We'll convert.
detector = FER(mtcnn=True) # robust face detector; set mtcnn=False if you want a bit more speed
EMOJI = {
"angry": "😠",
"disgust": "🀒",
"fear": "😨",
"happy": "πŸ˜„",
"sad": "😒",
"surprise": "😲",
"neutral": "😐",
}
def annotate_emotions(frame: np.ndarray):
"""
frame: HxWxC (uint8) in RGB from gradio webcam input
returns: (annotated_frame_RGB, top3_emotions_label_dict)
"""
if frame is None:
return None, {}
# Ensure uint8 RGB
img_rgb = frame.astype(np.uint8)
# Run FER
results = detector.detect_emotions(img_rgb) # list of {box: (x,y,w,h), emotions: {...}}
# Prepare overlay
annotated = img_rgb.copy()
# Collect aggregate scores for Label output
top_scores = {}
for r in results:
(x, y, w, h) = r["box"]
emotions = r["emotions"] # dict of emotion->score
# Top emotion for this face
if emotions:
top_em, top_score = sorted(emotions.items(), key=lambda kv: kv[1], reverse=True)[0]
# Draw rectangle
cv2.rectangle(annotated, (x, y), (x + w, y + h), (0, 255, 0), 2)
# Compose label with emoji
label = f"{EMOJI.get(top_em, '')} {top_em} {top_score:.2f}"
# Background for text
(tw, th), baseline = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.6, 2)
cv2.rectangle(annotated, (x, y - th - 10), (x + tw + 6, y), (0, 0, 0), -1)
cv2.putText(annotated, label, (x + 3, y - 6),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 2, cv2.LINE_AA)
# Keep the best score per emotion for the Label component
for k, v in emotions.items():
top_scores[k] = max(top_scores.get(k, 0.0), float(v))
# Sort and keep top-3 to keep the UI tidy
top3 = dict(sorted(top_scores.items(), key=lambda kv: kv[1], reverse=True)[:3])
# Gradio expects RGB; 'annotated' is already RGB
return annotated, top3
with gr.Blocks(fill_height=True) as demo:
gr.Markdown(
"""
# 🎭 Live Emotion Detection
- Allow camera access and look at the preview.
- The app detects faces and overlays the **top emotion** per face (plus confidence).
"""
)
with gr.Row():
with gr.Column(scale=3):
cam = gr.Image(sources=["webcam"], streaming=True, label="Webcam", height=420)
with gr.Column(scale=2):
out_img = gr.Image(label="Annotated", height=420)
out_label = gr.Label(label="Top emotions (global top-3)")
cam.stream(fn=annotate_emotions, inputs=cam, outputs=[out_img, out_label])
if __name__ == "__main__":
# Share=True is handy for quick testing on local networks
demo.launch()