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()