| name | video-analysis |
| description | Analyse vidéo — reconnaissance d'actions, pose estimation, video understanding, I3D, VideoMAE, TimeSformer, X3D, SlowFast, MediaPipe, Pose, OpenPose, VAD. En français. |
Analyse Vidéo — Actions, Pose, Compréhension Vidéo
Vision vidéo : reconnaître des actions, estimer des poses humaines, comprendre des séquences temporelles. Du classique (optical flow) aux transformers spatio-temporels (VideoMAE, TimeSformer).
1. Taxonomie de l'Analyse Vidéo
Analyse Vidéo
├── Reconnaissance d'Actions
│ ├── Two-Stream (RGB + Optical Flow) — I3D, Two-Stream
│ ├── 3D CNNs — C3D, I3D, X3D
│ ├── Video Transformers — TimeSformer, VideoMAE
│ └── Efficient (Mobile) — X3D, TSM
│
├── Pose Estimation Humaine
│ ├── Top-Down — HRNet, ViTPose
│ ├── Bottom-Up — OpenPose, DEKR
│ └── Lightweight — MediaPipe, MoveNet
│
├── Détection d'Anomalies Vidéo
│ ├── Reconstruction — AE, VAE, videoMAE
│ └── Prédiction — Future frame prediction
│
└── Video Understanding
├── Video Captioning — Texte → vidéo
├── Video QA — Questions sur vidéo
└── Temporal Action Detection (TAD) — Où/quand/quelles actions
2. Reconnaissance d'Actions
I3D (Inflated 3D ConvNets)
import torch
import torch.nn as nn
class InceptionI3D(nn.Module):
"""I3D : Inflated 3D Inception (pré-entraîné ImageNet inflaté vers vidéo)"""
def __init__(self, num_classes=400):
super().__init__()
self.conv1 = nn.Conv3d(3, 64, kernel_size=(7, 7, 7), stride=(2, 2, 2), padding=(3, 3, 3))
def forward(self, x):
return self.features(x)
from pytorchvideo.models import hub
i3d = hub.i3d_r50(pretrained=True)
slowfast = hub.slowfast_r50(pretrained=True)
x3d_xs = hub.x3d_xs(pretrained=True)
x3d_m = hub.x3d_m(pretrained=True)
model = slowfast.eval().cuda()
X3D (Expanding 3D Networks)
x3d_xs = hub.x3d_xs(pretrained=True)
x3d_s = hub.x3d_s(pretrained=True)
x3d_m = hub.x3d_m(pretrained=True)
x3d_l = hub.x3d_l(pretrained=True)
TimeSformer (Video Transformer)
from timesformer.models.vit import TimeSformer
model = TimeSformer(
img_size=224,
patch_size=16,
num_classes=400,
num_frames=8,
attention_type='divided_space_time',
pretrained_model='TimeSformer_divST_8x32_224_K400.pyth',
)
VideoMAE (Masked Autoencoders Video)
from transformers import VideoMAEForVideoClassification, VideoMAEImageProcessor
processor = VideoMAEImageProcessor.from_pretrained("MCG-NJU/videomae-base-finetuned-kinetics")
model = VideoMAEForVideoClassification.from_pretrained(
"MCG-NJU/videomae-base-finetuned-kinetics"
)
inputs = processor(list(video_frames[:16]), return_tensors="pt")
outputs = model(**inputs)
logits = outputs.logits
predicted_class = logits.argmax(-1).item()
3. Pose Estimation Humaine
MediaPipe (Lightweight, Temps Réel)
import mediapipe as mp
mp_pose = mp.solutions.pose
pose = mp_pose.Pose(
static_image_mode=True,
model_complexity=2,
enable_segmentation=True,
min_detection_confidence=0.5,
)
results = pose.process(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
if results.pose_landmarks:
for idx, landmark in enumerate(results.pose_landmarks.landmark):
h, w, _ = frame.shape
x, y = int(landmark.x * w), int(landmark.y * h)
cv2.circle(frame, (x, y), 3, (0, 255, 0), -1)
mp_hands = mp.solutions.hands
hands = mp_hands.Hands(max_num_hands=2)
mp_face_mesh = mp.solutions.face_mesh
face_mesh = mp_face_mesh.FaceMesh(max_num_faces=1)
mp_holistic = mp.solutions.holistic
holistic = mp_holistic.Holistic(min_detection_confidence=0.5)
OpenPose (Multi-Person)
ViTPose (Vision Transformer Pose)
from transformers import VitPoseForPoseEstimation
model = VitPoseForPoseEstimation.from_pretrained("ViTPose-base")
4. Pipeline Vidéo Complet
import cv2
import torch
import numpy as np
from collections import deque
class VideoActionDetector:
"""Détection d'actions en temps réel avec sliding window"""
def __init__(self, model, num_frames=16, stride=4):
self.model = model.eval().cuda()
self.num_frames = num_frames
self.stride = stride
self.frame_buffer = deque(maxlen=num_frames)
self.transform = ...
def process_frame(self, frame):
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
self.frame_buffer.append(frame_rgb)
if len(self.frame_buffer) < self.num_frames:
return None, frame
indices = np.linspace(0, len(self.frame_buffer)-1, self.num_frames, dtype=int)
clip = [self.frame_buffer[i] for i in indices]
clip_tensor = self.transform(clip).unsqueeze().cuda()
torch.no_grad():
logits = .model(clip_tensor)
probs = torch.softmax(logits, dim=)
top_k = torch.topk(probs, k=, dim=)
top_k, frame
cam = cv2.VideoCapture()
detector = VideoActionDetector(model, num_frames=, stride=)
:
ret, frame = cam.read()
predictions, annotated = detector.process_frame(frame)
predictions:
i ():
cls = predictions.indices[][i].item()
prob = predictions.values[][i].item()
label =
cv2.putText(annotated, label, (, + i*),
cv2.FONT_HERSHEY_SIMPLEX, , (, , ), )
cv2.imshow(, annotated)
5. Détection d'Anomalies Vidéo (VAD)
import torch
import torch.nn as nn
class VideoAnomalyDetector(nn.Module):
"""
Détection d'anomalies par prédiction de frame future.
Une grande erreur de reconstruction = anomalie.
"""
def __init__(self):
super().__init__()
self.encoder = nn.Sequential(
nn.Conv3d(3, 64, 3, 1, 1),
nn.ReLU(),
nn.MaxPool3d((1, 2, 2)),
nn.Conv3d(64, 128, 3, 1, 1),
nn.ReLU(),
nn.MaxPool3d((2, 2, 2)),
nn.Conv3d(128, 256, 3, 1, 1),
nn.ReLU(),
)
self.decoder = nn.Sequential(
nn.ConvTranspose3d(256, 128, 3, 1, 1),
nn.ReLU(),
nn.ConvTranspose3d(128, 64, 3, 1, 1),
nn.ReLU(),
nn.ConvTranspose3d(64, 3, 3, , ),
nn.Sigmoid(),
)
():
.decoder(.encoder(x))
():
mse = F.mse_loss(x, reconstructed, reduction=)
score = mse.mean(dim=[, , , ])
score
6. Temporal Action Detection (TAD)
def nms_temporal(proposals, iou_threshold=0.5):
"""Non-Maximum Suppression temporel"""
proposals = sorted(proposals, key=lambda x: x[3], reverse=True)
kept = []
while proposals:
best = proposals.pop(0)
kept.append(best)
proposals = [
p for p in proposals
if temporal_iou(best[:2], p[:2]) < iou_threshold
]
return kept
def temporal_iou(a, b):
"""IoU temporel entre deux segments [t1, t2]"""
inter = max(0, min(a[1], b[1]) - max(a[0], b[0]))
union = max(a[1], b[1]) - min(a[0], b[0])
return inter / union if union > 0 else 0
7. Datasets Vidéo
| Dataset | Clips | Classes | Tâche |
|---|
| Kinetics-400 | 300k | 400 | Action |
| Kinetics-700 | 650k | 700 | Action |
| UCF-101 | 13k | 101 | Action |
| HMDB-51 | 7k | 51 | Action |
| Something-Something v2 | 220k | 174 | Action fine |
| AVA | 430k | 80 | Action + localisation |
| Charades | 10k | 157 | Action maison |
| COCO Keypoints | 250k | 17 | Pose |
| MPII Human Pose | 25k | 16 | Pose |
| Penn Action | 2.3k | 15 | Pose action |
8. Optical Flow
import cv2
import numpy as np
prev_gray = cv2.cvtColor(frame1, cv2.COLOR_BGR2GRAY)
curr_gray = cv2.cvtColor(frame2, cv2.COLOR_BGR2GRAY)
flow = cv2.calcOpticalFlowFarneback(
prev_gray, curr_gray, None, 0.5, 3, 15, 3, 5, 1.2, 0,
)
mag, ang = cv2.cartToPolar(flow[..., 0], flow[..., 1])
hsv = np.zeros((flow.shape[0], flow.shape[1], 3), dtype=np.uint8)
hsv[..., 0] = ang * 180 / np.pi / 2
hsv[..., 1] = 255
hsv[..., 2] = cv2.normalize(mag, None, 0, 255, cv2.NORM_MINMAX)
flow_vis = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)
9. Datasets et Préparation
from torch.utils.data import Dataset
import decord
class VideoDataset(Dataset):
"""Dataset vidéo optimisé (decord + memmap)"""
def __init__(self, video_paths, labels, num_frames=32, frame_size=224):
self.video_paths = video_paths
self.labels = labels
self.num_frames = num_frames
self.frame_size = frame_size
self.transform = T.Compose([
T.Resize(frame_size),
T.CenterCrop(frame_size),
T.ToTensor(),
T.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
])
def __getitem__(self, idx):
vr = decord.VideoReader(self.video_paths[idx])
total_frames = len(vr)
indices = np.linspace(0, total_frames-1, self.num_frames, dtype=int)
frames = vr.get_batch(indices).asnumpy()
frames = torch.stack([self.transform(f) for f in frames])
frames.permute(, , , ), .labels[idx]
():
(.video_paths)
10. Évaluation
Benchmarks
| Modèle | Dataset | Métrique | Score |
|---|
| SlowFast R50 | Kinetics-400 | Top-1 | 79.1% |
| X3D-M | Kinetics-400 | Top-1 | 79.4% |
| TimeSformer-L | Kinetics-400 | Top-1 | 80.7% |
| VideoMAE-H | Kinetics-400 | Top-1 | 86.6% |
| ViTPose-B | COCO | mAP | 75.8 |
| HRNet-W48 | COCO | mAP | 76.3 |
| MediaPipe Pose | COCO | mAP | 69.3 |
Références