File size: 3,189 Bytes
0c46c35
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import os
import cv2
import numpy as np
import logging
from tensorflow.keras.models import load_model
from tensorflow.keras.preprocessing.image import img_to_array

# Define the exact labels from your notebook
EMOTION_LABELS = ['happy', 'sad', 'angry', 'surprised', 'neutral', 'fear', 'disgust']

class EmotionDetector:
    def __init__(self):
        self.model = None
        self.face_cascade = None
        self.load_resources()

    def load_resources(self):
        """Loads the ML model and Haar Cascade from the assets folder."""
        # Dynamic path to ensure it works on any machine
        base_path = os.path.dirname(os.path.abspath(__file__))
        assets_path = os.path.join(base_path, '..', 'ml_assets')

        model_path = os.path.join(assets_path, 'emotion_model_trained.h5')
        haar_path = os.path.join(assets_path, 'haarcascade_frontalface_default.xml')

        # Load Model
        try:
            self.model = load_model(model_path)
            logging.info(f"✅ Emotion Model loaded from {model_path}")
        except Exception as e:
            logging.error(f"❌ Failed to load model: {e}")

        # Load Face Detector
        try:
            self.face_cascade = cv2.CascadeClassifier(haar_path)
            if self.face_cascade.empty():
                raise IOError("Failed to load Haarcascade XML file")
            logging.info(f"✅ Face Detector loaded from {haar_path}")
        except Exception as e:
            logging.error(f"❌ Failed to load Haarcascade: {e}")

    def detect_emotion(self, image_path_or_array):
        """
        Input: Image (numpy array or file path)
        Output: Dictionary with 'emotion' and 'confidence'
        """
        if self.model is None or self.face_cascade is None:
            return {"error": "AI models are not loaded"}

        # 1. Read Image
        if isinstance(image_path_or_array, str):
            image = cv2.imread(image_path_or_array)
        else:
            image = image_path_or_array

        if image is None:
            return {"error": "Invalid image input"}

        # 2. Convert to Grayscale
        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

        # 3. Detect Face
        faces = self.face_cascade.detectMultiScale(gray, scaleFactor=1.3, minNeighbors=5)

        if len(faces) == 0:
            return {"message": "No face detected"}

        # 4. Process the first detected face
        (x, y, w, h) = faces[0]
        roi_gray = gray[y:y+h, x:x+w]
        
        # 5. Preprocessing (Resize to 48x48 & Normalize)
        roi = cv2.resize(roi_gray, (48, 48), interpolation=cv2.INTER_AREA)
        roi = roi.astype("float") / 255.0
        roi = img_to_array(roi)
        roi = np.expand_dims(roi, axis=0)

        # 6. Predict
        preds = self.model.predict(roi)[0]
        label_index = preds.argmax()
        label = EMOTION_LABELS[label_index]
        confidence = float(preds[label_index])

        return {
            "emotion": label,
            "confidence": round(confidence * 100, 2),
            "face_box": [int(x), int(y), int(w), int(h)]
        }

# Create a singleton instance to be imported elsewhere
emotion_detector = EmotionDetector()