Untitled

mail@pastecode.io avatar
unknown
plain_text
a month ago
11 kB
1
Indexable
Never
import cv2
import numpy as np
from deepface import DeepFace
import random
import time
import tensorflow as tf
import threading
from PIL import Image, ImageDraw, ImageFont
from gtts import gTTS
import os
import pygame
from io import BytesIO
import queue

# GPU Configuration
print("Số GPU khả dụng: ", len(tf.config.experimental.list_physical_devices('GPU')))
gpus = tf.config.experimental.list_physical_devices('GPU')
if gpus:
    try:
        for gpu in gpus:
            tf.config.experimental.set_memory_growth(gpu, True)
        logical_gpus = tf.config.experimental.list_logical_devices('GPU')
        print(len(gpus), "GPU vật lý,", len(logical_gpus), "GPU logic")
    except RuntimeError as e:
        print(e)
else:
    print("Không tìm thấy GPU. Đang chạy trên CPU.")

# List of emotions and corresponding emojis
emotions = {
    "tức giận": "😠", "ghê tởm": "🤢", "sợ hãi": "😨",
    "hạnh phúc": "😊", "buồn bã": "😢", "ngạc nhiên": "😲", "bình thường": "😐"
}

# Success time for each emotion (in seconds)
emotion_success_times = {
    "tức giận": 2.0, "ghê tởm": 1.5, "sợ hãi": 1.5,
    "hạnh phúc": 2.0, "buồn bã": 2.0, "ngạc nhiên": 1.5, "bình thường": 2.5
}

# Detailed guides for each emotion in Vietnamese
emotion_guides = {
    "tức giận": [
        "Nhíu mày mạnh, kéo lông mày lại gần nhau",
        "Mím môi hoặc đưa hàm dưới ra",
        "Mở to mắt, nhìn thẳng"
    ],
    "ghê tởm": [
        "Nhăn mũi, kéo môi trên lên",
        "Nheo mắt một chút",
        "Nghiêng đầu ra sau một chút"
    ],
    "sợ hãi": [
        "Mở to mắt, kéo lông mày lên",
        "Hé miệng một chút",
        "Ngả người ra sau nếu có thể"
    ],
    "hạnh phúc": [
        "Cười rộng, để lộ răng",
        "Nhướn mày lên một chút",
        "Để mắt sáng lên, có nếp nhăn ở đuôi mắt"
    ],
    "buồn bã": [
        "Kéo khóe miệng xuống",
        "Nhíu mày, tạo nếp nhăn giữa hai lông mày",
        "Hạ ánh mắt xuống, có thể nhìn xuống dưới"
    ],
    "ngạc nhiên": [
        "Mở to mắt, nâng lông mày cao",
        "Hé miệng, hạ hàm dưới xuống một chút",
        "Tạo nếp nhăn trên trán"
    ],
    "bình thường": [
        "Thả lỏng các cơ mặt",
        "Giữ miệng khép, nhưng không chặt",
        "Nhìn thẳng với ánh mắt bình tĩnh"
    ]
}

# Colors for different types of text
COLORS = {
    'target': (255, 105, 180),  # Hồng đậm
    'success': (0, 255, 0),  # Xanh lá
    'error': (0, 0, 255),  # Đỏ
    'info': (255, 165, 0)  # Cam
}

# Hàng đợi âm thanh và biến kiểm soát
audio_queue = queue.Queue()
playback_lock = threading.Lock()

# Initialize pygame mixer for audio playback
pygame.mixer.init()

# Load a font that supports Vietnamese
font = ImageFont.truetype("arial.ttf", 16)

# Tạo hàng đợi cho các yêu cầu phát âm thanh
speech_queue = queue.Queue()

# Biến để kiểm soát việc dừng âm thanh
stop_current_speech = threading.Event()

# Hàm để phát âm thanh từ BytesIO object
def play_sound(sound_bytes):
    with playback_lock:
        sound = pygame.mixer.Sound(sound_bytes)
        sound.play()
        while pygame.mixer.get_busy():
            if stop_current_speech.is_set():
                pygame.mixer.stop()  # Stop current sound playback
                break
            time.sleep(0.1)

# Hàm xử lý hàng đợi âm thanh
def process_speech_queue():
    while True:
        text = speech_queue.get()
        if text is None:
            break
        try:
            if stop_current_speech.is_set():
                pygame.mixer.stop()  # Ensure any ongoing playback is stopped
                stop_current_speech.clear()

            tts = gTTS(text=text, lang='vi')
            fp = BytesIO()
            tts.write_to_fp(fp)
            fp.seek(0)
            play_sound(fp)
        except Exception as e:
            print(f"Lỗi khi phát âm thanh: {e}")
        speech_queue.task_done()

# Bắt đầu luồng xử lý âm thanh
speech_thread = threading.Thread(target=process_speech_queue, daemon=True)
speech_thread.start()

def speak(text):
    """Hàm chuyển văn bản thành giọng nói"""
    speech_queue.put(text)

def cv2_im_to_pil(cv2_im):
    return Image.fromarray(cv2.cvtColor(cv2_im, cv2.COLOR_BGR2RGB))

def pil_to_cv2_im(pil_im):
    return cv2.cvtColor(np.array(pil_im), cv2.COLOR_RGB2BGR)

def draw_text_with_pil(cv2_im, text, position, font, text_color=(255, 255, 255)):
    pil_im = cv2_im_to_pil(cv2_im)
    draw = ImageDraw.Draw(pil_im)
    draw.text(position, text, font=font, fill=text_color)
    return pil_to_cv2_im(pil_im)

def display_emotion_and_feedback(frame, target_emotion, feedback, detected_emotion=None):
    """Hiển thị cảm xúc mục tiêu và phản hồi trên khung hình"""
    height, width, _ = frame.shape

    text = f"Hãy thể hiện cảm xúc: {emotions.get(target_emotion, '?')} ({target_emotion})"
    frame = draw_text_with_pil(frame, text, (10, 15), font, COLORS['target'])

    y_offset = 45
    color = COLORS['success'] if "Tuyệt vời" in feedback else COLORS['error']
    for line in feedback.split('\n'):
        frame = draw_text_with_pil(frame, line, (10, y_offset), font, color)
        y_offset += 22

    if detected_emotion:
        text = f"Cảm xúc phát hiện: {emotions.get(detected_emotion, '?')} ({detected_emotion})"
        frame = draw_text_with_pil(frame, text, (10, height - 30), font, COLORS['info'])

    return frame

def analyze_emotion(frame):
    """Phân tích cảm xúc sử dụng DeepFace"""
    try:
        with tf.device('/GPU:0'):
            result = DeepFace.analyze(frame, actions=['emotion'], enforce_detection=False)
        detected_emotion = result[0]['dominant_emotion']
        # Map English emotion to Vietnamese
        emotion_map = {
            "angry": "tức giận", "disgust": "ghê tởm", "fear": "sợ hãi",
            "happy": "hạnh phúc", "sad": "buồn bã", "surprise": "ngạc nhiên",
            "neutral": "bình thường"
        }
        return emotion_map.get(detected_emotion, "unknown")
    except Exception as e:
        print(f"Lỗi khi phân tích cảm xúc: {e}")
        return "unknown"

def give_feedback(expected_emotion, detected_emotion):
    """Đưa ra phản hồi dựa trên cảm xúc phát hiện được"""
    if expected_emotion == detected_emotion:
        feedback = f"Tuyệt vời! Bạn đã thể hiện chính xác cảm xúc {expected_emotion}."
    elif detected_emotion == "unknown":
        feedback = "Không thể phát hiện cảm xúc. Hãy thử lại và đảm bảo khuôn mặt của bạn được nhìn thấy rõ ràng."
    else:
        feedback = f"Bạn đang thể hiện {detected_emotion}, không phải {expected_emotion}.\n"
        feedback += "Hãy thử lại với những gợi ý sau:\n"
        for guide in emotion_guides.get(expected_emotion, []):
            feedback += f"- {guide}\n"

    speak(feedback)
    return feedback

def congratulate(emotion, duration):
    """Đưa ra lời chúc mừng chi tiết hơn"""
    congratulation = f"Xuất sắc! Bạn đã giữ được biểu cảm {emotion} trong {duration:.1f} giây. "
    congratulation += "Khả năng kiểm soát khuôn mặt của bạn thật ấn tượng. "
    congratulation += "Hãy tiếp tục phát huy và thử thách bản thân với cảm xúc tiếp theo!"

    print(congratulation)
    speak(congratulation)

    congrats_image = np.zeros((200, 400, 3), dtype=np.uint8)
    congrats_image = draw_text_with_pil(congrats_image, "Chúc mừng!", (30, 30), font, (0, 255, 0))
    congrats_image = draw_text_with_pil(congrats_image, f"Bạn đã thể hiện {emotion}", (30, 70), font, (255, 255, 255))
    congrats_image = draw_text_with_pil(congrats_image, f"trong {duration:.1f} giây!", (30, 110), font, (255, 255, 255))
    congrats_image = draw_text_with_pil(congrats_image, "Làm tốt lắm!", (30, 150), font, (0, 255, 255))

    cv2.imshow("Chúc mừng!", congrats_image)
    cv2.waitKey(5000)  # Hiển thị trong 5 giây
    cv2.destroyWindow("Chúc mừng!")

def main():
    print("Chào mừng đến với Trò chơi Nhận diện Cảm xúc!")
    speak("Chào mừng đến với Trò chơi Nhận diện Cảm xúc!")
    print("Nhấn 'q' để thoát trò chơi bất cứ lúc nào.")
    speak("Nhấn q để thoát trò chơi bất cứ lúc nào.")

    cv2.namedWindow('Trò chơi Nhận diện Cảm xúc', cv2.WINDOW_NORMAL)
    cv2.resizeWindow('Trò chơi Nhận diện Cảm xúc', 800, 600)

    cap = cv2.VideoCapture(0)

    target_emotion = random.choice(list(emotions.keys()))
    speak(f"Hãy bắt đầu với cảm xúc {target_emotion}")
    success_time = None
    last_analysis_time = 0
    analysis_interval = 1.0  # Phân tích mỗi 1 giây

    feedback = "Hãy bắt đầu thể hiện cảm xúc!"
    detected_emotion = None

    while True:
        ret, frame = cap.read()
        if not ret:
            break

        current_time = time.time()

        # Phân tích cảm xúc theo khoảng thời gian
        if current_time - last_analysis_time > analysis_interval:
            detected_emotion = analyze_emotion(frame)
            last_analysis_time = current_time

            if target_emotion == detected_emotion:
                if success_time is None:
                    success_time = current_time
                elif current_time - success_time >= emotion_success_times[target_emotion]:
                    duration = current_time - success_time
                    congratulate(target_emotion, duration)
                    target_emotion = random.choice(list(emotions.keys()))
                    speak(f"Bây giờ, hãy thử thể hiện {target_emotion}")
                    success_time = None
                    feedback = "Hãy bắt đầu thể hiện cảm xúc mới!"
                    stop_current_speech.set()  # Ensure current speech stops
            else:
                success_time = None
                feedback = give_feedback(target_emotion, detected_emotion)

        frame = display_emotion_and_feedback(frame, target_emotion, feedback, detected_emotion)
        cv2.imshow('Trò chơi Nhận diện Cảm xúc', frame)

        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

    cap.release()
    cv2.destroyAllWindows()
    print("Cảm ơn bạn đã chơi!")
    speak("Cảm ơn bạn đã chơi!")

    # Dừng luồng xử lý âm thanh
    speech_queue.put(None)
    speech_thread.join()
    pygame.mixer.quit()

if __name__ == "__main__":
    main()
Leave a Comment