import cv2 import torch import torch.nn.functional as F from PIL import Image def analyze_video(video_path, vision_model, transform): """ Extrait 1 frame par seconde sur max 10 secondes. Détecte le visage, recadre et analyse avec vision_model. """ cap = cv2.VideoCapture(video_path) if not cap.isOpened(): raise Exception("Impossible de lire la vidéo.") fps = cap.get(cv2.CAP_PROP_FPS) if fps <= 0: fps = 30 # Fallback approximatif # Initialisation du détecteur de visage OpenCV (Haar Cascade) face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml') frames_extracted = [] max_seconds = 10 total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) for sec in range(max_seconds): frame_idx = int(fps * sec) if frame_idx >= total_frames: break cap.set(cv2.CAP_PROP_POS_FRAMES, frame_idx) ret, frame = cap.read() if not ret: break # Conversion du frame en niveaux de gris pour la détection gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # Détection des visages faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30)) if len(faces) == 0: # Si on ne trouve pas de visage, on ignore simplement la frame continue # Recadrage sur le premier pseudo-visage (le plus saillant) (x, y, w, h) = faces[0] face_roi = frame[y:y+h, x:x+w] # Conversion BGR -> RGB du visage recadré face_rgb = cv2.cvtColor(face_roi, cv2.COLOR_BGR2RGB) # Conversion en PIL Image img_pil = Image.fromarray(face_rgb) frames_extracted.append(img_pil) cap.release() if not frames_extracted: raise Exception("Aucune frame avec un visage n'a pu être extraite. La vidéo est soit vide, soit aucun visage n'est visible.") # Device où le modèle est chargé device = next(vision_model.parameters()).device fake_probs = [] for img in frames_extracted: img_tensor = transform(img).unsqueeze(0).to(device) with torch.no_grad(): outputs = vision_model(img_tensor) # Calcul explicite des probabilités via softmax probabilities = F.softmax(outputs, dim=1)[0] # Index 0 = Fake/IA prob_fake = float(probabilities[0].item()) fake_probs.append(prob_fake) # Le score moyen de probabilité "Fake" average_fake_prob = sum(fake_probs) / len(fake_probs) # Décision stricte : la moyenne des probabilités IA doit dépasser 75% if average_fake_prob > 0.75: return {"prediction": "IA", "probability": average_fake_prob} else: return {"prediction": "Humain", "probability": 1.0 - average_fake_prob}