Spaces:
No application file
No application file
Upload programme5_Jalon4.py
#21
by JeanBaptiste2526 - opened
- programme5_Jalon4.py +79 -0
programme5_Jalon4.py
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import cv2 # utile pour la gestion de la vidéo
|
| 2 |
+
import mediapipe as mp # utile pour gérer la détection de visages
|
| 3 |
+
import json # utile pour l'exportation en json
|
| 4 |
+
|
| 5 |
+
face_mesh = mp.solutions.face_mesh.FaceMesh() # on initialise le modèle de détection du visage
|
| 6 |
+
cap = cv2.VideoCapture("video.mp4") # on ouvre la vidéo en mp4 via cv2
|
| 7 |
+
fps = cap.get(cv2.CAP_PROP_FPS) # récupère le nombre de fps
|
| 8 |
+
frame_index = 0 # compteur de frames, sert à calculer les timestamps
|
| 9 |
+
data = [] # contiendra tous les landmarks de toutes les frames, vide pour l'instant
|
| 10 |
+
|
| 11 |
+
while True:
|
| 12 |
+
ret, video = cap.read() # on lit la frame suivante de la vidéo
|
| 13 |
+
if ret is not True:
|
| 14 |
+
break # plus rien à lire, on sort
|
| 15 |
+
|
| 16 |
+
height, width, _ = video.shape # on récupère les dimensions de la frame
|
| 17 |
+
result = face_mesh.process(video) # cherche un visage sur la vidéo
|
| 18 |
+
|
| 19 |
+
for facial_landmarks in result.multi_face_landmarks: # on parcourt le visage
|
| 20 |
+
xb = [] # utile pour les coordonnées de la boîte englobante
|
| 21 |
+
yb = [] # utile pour les coordonnées de la boîte englobante
|
| 22 |
+
|
| 23 |
+
for pt in facial_landmarks.landmark: # on parcourt chaque point facial
|
| 24 |
+
x = int(pt.x * width) # calcul des coordonnées des pixels
|
| 25 |
+
y = int(pt.y * height) # calcul des coordonnées des pixels
|
| 26 |
+
xb.append(x) # on stocke les coordonnées pour calculer la boîte englobante
|
| 27 |
+
yb.append(y) # on stocke les coordonnées pour calculer la boîte englobante
|
| 28 |
+
cv2.circle(video, (x, y), 2, (100, 100, 0), -1) # on dessine un petit cercle sur chaque point du visage
|
| 29 |
+
|
| 30 |
+
cv2.rectangle(video, (min(xb), min(yb)), (max(xb), max(yb)), (0, 255, 0), 2) # boîte englobante verte autour du visage
|
| 31 |
+
|
| 32 |
+
if frame_index % round(fps / 4) == 0:
|
| 33 |
+
lm = facial_landmarks.landmark # raccourci pour accéder aux points
|
| 34 |
+
face_x = lm[1].x * width # position X du nez dans l'image
|
| 35 |
+
face_y = lm[1].y * height # position Y du nez dans l'image
|
| 36 |
+
|
| 37 |
+
centre_x = width / 2 # centre horizontal de l'image
|
| 38 |
+
centre_y = height / 2 # centre vertical de l'image
|
| 39 |
+
|
| 40 |
+
head_yaw = (face_x - centre_x) / centre_x * 90 # rotation gauche/droite
|
| 41 |
+
head_pitch = (face_y - centre_y) / centre_y * 90 # rotation haut/bas
|
| 42 |
+
|
| 43 |
+
mouth_open = abs(lm[14].y - lm[13].y) * height # ouverture de la bouche en pixels
|
| 44 |
+
|
| 45 |
+
mouth_width = abs(lm[61].x - lm[291].x) * width # largeur de la bouche en pixels (détection du sourire)
|
| 46 |
+
|
| 47 |
+
eye_open = abs(lm[159].y - lm[145].y) * height # ouverture de l'oeil gauche en pixels
|
| 48 |
+
|
| 49 |
+
face_width = max(xb) - min(xb) # largeur du visage en pixels
|
| 50 |
+
smile = mouth_width > 0.40 * face_width # sourire si bouche > 40% de la largeur du visage
|
| 51 |
+
|
| 52 |
+
eyes_wide = eye_open > 8 # yeux grands ouverts si ouverture > 8 pixels (surprise)
|
| 53 |
+
|
| 54 |
+
if mouth_open > 10: # bouche ouverte ==> antennes levées symétriquement
|
| 55 |
+
antenna_angle = 45
|
| 56 |
+
elif smile: # sourire ==> antennes en V
|
| 57 |
+
antenna_angle = 30
|
| 58 |
+
else:
|
| 59 |
+
antenna_angle = 0 # neutre ==> antennes baissées
|
| 60 |
+
|
| 61 |
+
data.append({
|
| 62 |
+
"timestamp": round(frame_index / fps, 1),
|
| 63 |
+
"mouth_open": round(mouth_open, 2),
|
| 64 |
+
"antennas": antenna_angle,
|
| 65 |
+
"smile": smile,
|
| 66 |
+
"eyes_wide": eyes_wide, # yeux grands ouverts ou non
|
| 67 |
+
"head_pitch": round(head_pitch, 2),
|
| 68 |
+
"head_yaw": round(head_yaw, 2)
|
| 69 |
+
})
|
| 70 |
+
|
| 71 |
+
cv2.imshow("Video", video) # on affiche la vidéo
|
| 72 |
+
cv2.waitKey(1) # on laisse 1ms à OpenCV pour afficher la frame
|
| 73 |
+
frame_index = frame_index + 1 # on passe à la frame suivante
|
| 74 |
+
|
| 75 |
+
with open("results.json", "w") as file: # on ouvre le fichier en écriture
|
| 76 |
+
json.dump(data, file, indent=2) # on écrit les données
|
| 77 |
+
|
| 78 |
+
cap.release() # on ferme la vidéo
|
| 79 |
+
cv2.destroyAllWindows() # ferme toutes les fenêtres
|