import json import math #Identifie l'émotion grace à une combinaison de muscles faciaux def trouver_emotion(donnees): if donnees.get("mouth_smile", 0) > 0.15: return "Joie" elif (donnees.get("brow_outer_up", 0) > 0.08 and donnees.get("eye_wide", 0) > 0.08 and donnees.get("mouth_open", 0) > 0.08): return "Surprise" elif (donnees.get("brow_outer_up", 0) > 0.05 and donnees.get("eye_wide", 0) > 0.05 and donnees.get("mouth_open", 0) > 0.05): return "Peur" elif donnees.get("brow_inner_up", 0) > 0.15: return "Tristesse" elif (donnees.get("brow_furrow", 0) > 0.15 and donnees.get("mouth_press", 0) > 0.1): return "Colere" return "Neutre" # Génère les trajectoires des antennes du robot pour exprimer une émotion. def calculer_cibles_antennes(emotion, temps_ecoule): if emotion == "Joie": bouge = math.radians(30 * math.sin(2 * math.pi * 0.5 * temps_ecoule)) return 0.0, bouge, 0.0, bouge elif emotion == "Colere": tremble = math.radians(6 * math.sin(2 * math.pi * 8 * temps_ecoule)) return math.radians(20), math.radians(-70) + tremble, math.radians(20), math.radians(70) - tremble elif emotion == "Peur": tremble = math.radians(6 * math.sin(2 * math.pi * 10 * temps_ecoule)) return 0.0, math.radians(-160) + tremble, 0.0, math.radians(160) - tremble elif emotion == "Surprise": x = math.radians(15 * math.sin(2 * math.pi * 3 * temps_ecoule)) y = math.radians(10 * math.cos(2 * math.pi * 3 * temps_ecoule)) return 0.0, x + y, 0.0, -(x - y) elif emotion == "Tristesse": ratio = min(temps_ecoule / 2.0, 1.0) return 0.0, math.radians(-160 * ratio), 0.0, math.radians(160 * ratio) return 0.0, 0.0, 0.0, 0.0 # Fonction de danse d'attente def calculer_danse_antennes(temps_ecoule): vague_x = math.radians(45 * math.sin(2 * math.pi * 2.5 * temps_ecoule)) vague_y = math.radians(45 * math.cos(2 * math.pi * 2.5 * temps_ecoule)) return vague_x, vague_y, vague_y, vague_x def adoucir_mouvement(position_actuelle, position_cible, vitesse): return position_actuelle + vitesse * (position_cible - position_actuelle) # Converti un JSON de signaux en JSON de mouvements. def generer_mouvement(input_json, output_json): with open(input_json, 'r', encoding='utf-8') as f: donnees_video = json.load(f)["face_data"] frames_robot = [] emotion_validee = "Neutre" emotion_en_cours = "Neutre" confirmations = 0 chronometre_emotion = 0.0 if not donnees_video: return image_depart = donnees_video[0] tete_p, tete_y, tete_r = image_depart.get("pitch", 0.0), image_depart.get("yaw", 0.0), image_depart.get("roll", 0.0) ant_g_p, ant_g_r = 0.0, 0.0 ant_d_p, ant_d_r = 0.0, 0.0 for frame in donnees_video: if not frame["face_detected"]: continue temps_actuel = frame["timestamp"] emotion_detectee = trouver_emotion(frame) if emotion_detectee == emotion_en_cours: confirmations += 1 else: emotion_en_cours = emotion_detectee confirmations = 1 # Validation du changement d'état émotionnel if confirmations >= 5 and emotion_en_cours != emotion_validee: emotion_validee = emotion_en_cours chronometre_emotion = temps_actuel temps_animation = temps_actuel - chronometre_emotion cible_tete_p, cible_tete_y, cible_tete_r = frame["pitch"], frame["yaw"], frame["roll"] cible_ag_p, cible_ag_r, cible_ad_p, cible_ad_r = calculer_cibles_antennes(emotion_validee, temps_animation) tete_p = adoucir_mouvement(tete_p, cible_tete_p, vitesse=0.6) tete_y = adoucir_mouvement(tete_y, cible_tete_y, vitesse=0.6) tete_r = adoucir_mouvement(tete_r, cible_tete_r, vitesse=0.6) ant_g_p = adoucir_mouvement(ant_g_p, cible_ag_p, vitesse=0.5) ant_g_r = adoucir_mouvement(ant_g_r, cible_ag_r, vitesse=0.5) ant_d_p = adoucir_mouvement(ant_d_p, cible_ad_p, vitesse=0.5) ant_d_r = adoucir_mouvement(ant_d_r, cible_ad_r, vitesse=0.5) frames_robot.append({ "timestamp": temps_actuel, "head": {"pitch": tete_p, "yaw": tete_y, "roll": tete_r}, "body_yaw": 0.0, "antennas": { "left": {"pitch": ant_g_p, "roll": ant_g_r}, "right": {"pitch": ant_d_p, "roll": ant_d_r} } }) with open(output_json, 'w', encoding='utf-8') as f: json.dump({"mouvements": frames_robot}, f, indent=4) if __name__ == "__main__": generer_mouvement("../data/signaux_extraits.json", "../data/mouvement_reachy.json")