import cv2 import numpy as np import base64 import logging from deepface import DeepFace from typing import Dict, Tuple, Optional # Configure logging logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') logger = logging.getLogger("EmotionProcessor") class EmotionProcessor: def __init__(self): """Initialize the emotion processor.""" try: # Load face cascade classifier self.face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml') logger.info("Emotion processor initialized successfully") except Exception as e: logger.error(f"Failed to initialize emotion processor: {e}") raise def process_base64_image(self, base64_image: str) -> Tuple[Optional[str], Optional[Dict]]: """Process a base64 encoded image and return the dominant emotion.""" try: # Remove data URL prefix if present if ',' in base64_image: base64_image = base64_image.split(',')[1] # Decode base64 image img_data = base64.b64decode(base64_image) nparr = np.frombuffer(img_data, np.uint8) frame = cv2.imdecode(nparr, cv2.IMREAD_COLOR) if frame is None: logger.error("Failed to decode image") return None, None return self.process_frame(frame) except Exception as e: logger.error(f"Error processing base64 image: {e}") return None, None def process_frame(self, frame) -> Tuple[Optional[str], Optional[Dict]]: """Process a frame and return the dominant emotion.""" try: # Convert frame to grayscale gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # Convert grayscale frame to RGB format rgb_frame = cv2.cvtColor(gray_frame, cv2.COLOR_GRAY2RGB) # Detect faces in the frame faces = self.face_cascade.detectMultiScale(gray_frame, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30)) if len(faces) == 0: logger.info("No faces detected") return "neutral", None # Process the first face x, y, w, h = faces[0] # Extract the face ROI (Region of Interest) face_roi = rgb_frame[y:y + h, x:x + w] # Perform emotion analysis on the face ROI result = DeepFace.analyze(face_roi, actions=['emotion'], enforce_detection=False) # Determine the dominant emotion emotion = result[0]['dominant_emotion'] emotion_scores = result[0]['emotion'] logger.info(f"Detected emotion: {emotion}") return emotion, emotion_scores except Exception as e: logger.error(f"Error processing frame: {e}") return "neutral", None # For testing if __name__ == "__main__": processor = EmotionProcessor() # Test with a sample image if available # result = processor.process_frame(cv2.imread('sample.jpg')) # print(f"Detected emotion: {result}")