Spaces:
Running
Running
| 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} | |