Temporele manipulatie & frame-injectie
Technieken voor het injecteren van adversariële frames in videostreams, temporele consistentieaanvallen en single-frame-injectie voor gedragsverandering in video-AI-modellen.
Framebemonstering exploiteren
Videomodellen verwerken slechts een subset van frames. Door zich te richten op de bemonsteringsstrategie kunnen aanvallers ervoor zorgen dat hun adversariële content wordt verwerkt, terwijl deze ondetecteerbaar blijft in de bredere video.
Bemonsterde frames voorspellen
import numpy as np
from typing import List
def predict_sampled_indices(
total_frames: int,
num_samples: int = 16,
strategy: str = "uniform"
) -> List[int]:
"""
Voorspel welke frames een videomodel zal bemonsteren.
Veelvoorkomende strategieën:
- uniform: gelijkmatig verdeelde frames
- center: frames rond het temporele centrum
- random_uniform: willekeurig met uniforme dekking
"""
if strategy == "uniform":
return [int(i * total_frames / num_samples) for i in range(num_samples)]
elif strategy == "center":
center = total_frames // 2
half = num_samples // 2
step = max(1, total_frames // (num_samples * 2))
return [center - half * step + i * step for i in range(num_samples)]
elif strategy == "random_uniform":
# Verdeel in segmenten, bemonster er één uit elk
segment_size = total_frames // num_samples
return [
np.random.randint(i * segment_size, (i + 1) * segment_size)
for i in range(num_samples)
]
else:
raise ValueError(f"Unknown strategy: {strategy}")Gerichte frame-injectie
Vervang of modificeer alleen de frames die bemonsterd zullen worden:
import cv2
import numpy as np
def inject_adversarial_frames(
video_path: str,
output_path: str,
adversarial_frame: np.ndarray,
num_model_samples: int = 16
) -> dict:
"""
Injecteer adversariële content in precies de frames
die het doel-videomodel zal bemonsteren.
"""
cap = cv2.VideoCapture(video_path)
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
fps = cap.get(cv2.CAP_PROP_FPS)
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
# Voorspel welke frames bemonsterd zullen worden
target_indices = set(predict_sampled_indices(total_frames, num_model_samples))
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter(output_path, fourcc, fps, (width, height))
frame_idx = 0
injected_count = 0
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
if frame_idx in target_indices:
# Meng adversariële content met origineel frame
adv_resized = cv2.resize(adversarial_frame, (width, height))
blended = cv2.addWeighted(frame, 0.7, adv_resized, 0.3, 0)
out.write(blended)
injected_count += 1
else:
out.write(frame)
frame_idx += 1
cap.release()
out.release()
return {
"total_frames": total_frames,
"injected_frames": injected_count,
"injection_rate": f"{injected_count/total_frames:.1%}"
}Single-frame-injectie
Een bijzonder krachtige aanval: het invoegen van één enkel adversarieel frame dat het begrip van het model van de hele video verandert.
Implementatie
def single_frame_injection(
video_path: str,
injection_frame: np.ndarray,
injection_position: float = 0.5, # 0-1, positie in video
output_path: str = "injected.mp4"
) -> str:
"""
Voeg één enkel adversarieel frame in op een specifieke positie.
De positie moet samenvallen met een waarschijnlijk bemonsteringspunt.
Voor uniforme bemonstering van 16 frames wordt het middelste frame
(positie 0.5) altijd bemonsterd.
"""
cap = cv2.VideoCapture(video_path)
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
fps = cap.get(cv2.CAP_PROP_FPS)
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
target_frame = int(total_frames * injection_position)
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter(output_path, fourcc, fps, (width, height))
frame_idx = 0
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
if frame_idx == target_frame:
adv_resized = cv2.resize(injection_frame, (width, height))
out.write(adv_resized)
else:
out.write(frame)
frame_idx += 1
cap.release()
out.release()
return output_pathTekst-in-frame-injectie voor video-LLM's
Voor op LLM gebaseerde videobegripsystemen injecteer je een frame met tekstinstructies:
from PIL import Image, ImageDraw, ImageFont
def create_text_injection_frame(
instruction: str,
width: int = 1920,
height: int = 1080,
bg_color: tuple = (0, 0, 0)
) -> np.ndarray:
"""Maak een frame met injectie-instructies voor video-LLM's."""
img = Image.new("RGB", (width, height), bg_color)
draw = ImageDraw.Draw(img)
try:
font = ImageFont.truetype(
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 36
)
except OSError:
font = ImageFont.load_default()
# Witte tekst op zwart -- hoog contrast voor OCR
draw.text((50, height // 2 - 50), instruction, fill="white", font=font)
return np.array(img)Temporele consistentieaanvallen
Deze aanvallen voegen perturbaties toe die onmerkbaar zijn in elk afzonderlijk frame, maar coherente adversariële signalen creëren over de temporele dimensie.
Flikkerperturbatie
def temporal_flicker_attack(
frames: List[np.ndarray],
perturbation: np.ndarray,
frequency: int = 2 # Toggle every N frames
) -> List[np.ndarray]:
"""
Pas perturbatie toe in een afwisselend patroon.
De perturbatie middelt visueel uit (flikkering is moeilijk op te merken
bij hoge frequenties) maar beïnvloedt temporele features die door
het model worden geëxtraheerd.
"""
result = []
for i, frame in enumerate(frames):
if (i // frequency) % 2 == 0:
perturbed = np.clip(frame + perturbation, 0, 255).astype(np.uint8)
else:
perturbed = np.clip(frame - perturbation, 0, 255).astype(np.uint8)
result.append(perturbed)
return resultProgressieve perturbatie
Een perturbatie geleidelijk vergroten in de tijd, waardoor elke verandering van frame tot frame onmerkbaar wordt:
def progressive_perturbation(
frames: List[np.ndarray],
target_perturbation: np.ndarray,
start_frame: int = 0,
duration_frames: int = 30
) -> List[np.ndarray]:
"""
Pas perturbatie geleidelijk toe over meerdere frames.
Elk frame verschilt slechts een klein beetje van het vorige.
"""
result = []
for i, frame in enumerate(frames):
if i < start_frame or i >= start_frame + duration_frames:
result.append(frame)
else:
progress = (i - start_frame) / duration_frames
current_pert = target_perturbation * progress
perturbed = np.clip(frame + current_pert, 0, 255).astype(np.uint8)
result.append(perturbed)
return resultEffectiviteit van aanvallen per architectuur
| Architectuur | Meest effectieve aanval | Reden |
|---|---|---|
| TimeSformer | Single-frame-injectie | Verdeelde attention laat één frame domineren |
| VideoMAE | Multi-frame-perturbatie | Op masking gebaseerde training is robuust tegen afzonderlijke frames |
| Video-LLaVA | Tekst-in-frame-injectie | LLM-backbone leest geïnjecteerde tekst |
| SlowFast | Temporele flikkering | Dual-pathway-architectuur is gevoelig voor temporele patronen |
| I3D / C3D | 3D-convolutie-adversarieel | 3D-kernels overspannen aangrenzende frames |
Gerelateerde onderwerpen
- Video Model Attacks Overview -- bredere context van videobeveiliging
- Image-Based Prompt Injection -- injectietechnieken per frame
- Video Understanding Model Exploitation -- video-aanvallen op semantisch niveau
Referenties
- "Adversarial Attacks on Video Recognition Models" - Wei et al. (2022) - Temporal perturbation strategies for video models
- "Flickering Adversarial Perturbations for Video Understanding" - Pony et al. (2021) - Temporal flicker-based attacks targeting video temporal features
- "TimeSformer: Is Space-Time Attention All You Need for Video Understanding?" - Bertasius et al. (2021) - Architecture details relevant to temporal attention exploitation
- "Physical Adversarial Attacks on Video Classification Models" - Li et al. (2019) - Frame injection strategies in physical environments
Waarom is single-frame-injectie effectief tegen videomodellen die attention over frames gebruiken?