AI Agents · Lección

Comprensión de vídeo en agentes

Extracción de fotogramas, resumen de vídeos y razonamiento temporal sobre clips.

Lección 3 de 413 pasos

Comprensión de vídeo en agentes es una lección gratuita de AI Agents en CoddyKit. Esta es la lección 3 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de AI Agents, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de AI Agents incluye 4 lecciones en total.

Comprensión de vídeo para agentes

La mayoría de los LLM no pueden procesar directamente archivos de vídeo, pero los agentes pueden analizarlos extrayendo fotogramas representativos y enviándolos como imágenes. Después, el agente razona sobre la secuencia visual para detectar eventos, cambios y patrones a lo largo del tiempo.

Instalación de OpenCV para extraer fotogramas

OpenCV (cv2) es la biblioteca estándar para procesar vídeo en Python. Permite abrir archivos de vídeo, leer sus metadatos (frecuencia de fotogramas, resolución y cantidad de fotogramas) y extraer fotogramas individuales como arrays de NumPy.

# pip install opencv-python-headless
import cv2

def get_video_metadata(video_path: str) -> dict:
    cap = cv2.VideoCapture(video_path)
    if not cap.isOpened():
        raise IOError(f'Cannot open video: {video_path}')

    fps = cap.get(cv2.CAP_PROP_FPS)
    frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
    width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    duration_s = frame_count / fps if fps > 0 else 0
    cap.release()

    return {
        'fps': round(fps, 2),
        'frame_count': frame_count,
        'width': width,
        'height': height,
        'duration_seconds': round(duration_s, 2)
    }

meta = get_video_metadata('recording.mp4')
print(meta)

Extracción de fotogramas cada N segundos

Para la mayoría de las tareas de comprensión de vídeo, no necesita todos los fotogramas. Muestrear un fotograma cada N segundos proporciona un resumen representativo del contenido del vídeo. A 1 fotograma por segundo, un vídeo de 60 segundos produce 60 fotogramas.

import cv2
import os

def extract_frames(
    video_path: str,
    output_dir: str,
    every_n_seconds: float = 5.0
) -> list:
    cap = cv2.VideoCapture(video_path)
    fps = cap.get(cv2.CAP_PROP_FPS)
    frame_interval = int(fps * every_n_seconds)
    os.makedirs(output_dir, exist_ok=True)

    saved_frames = []
    frame_idx = 0
    while True:
        ret, frame = cap.read()
        if not ret:
            break
        if frame_idx % frame_interval == 0:
            timestamp = round(frame_idx / fps, 2)
            fname = f'{output_dir}/frame_{frame_idx:06d}_{timestamp}s.jpg'
            cv2.imwrite(fname, frame)
            saved_frames.append({'path': fname, 'timestamp': timestamp})
        frame_idx += 1

    cap.release()
    print(f'Extracted {len(saved_frames)} frames')
    return saved_frames

Detección de cambios de escena

En lugar de realizar un muestreo uniforme, extraiga fotogramas en los límites de las escenas, es decir, en los momentos en que el contenido visual cambia significativamente. Esto proporciona fotogramas más informativos en cada llamada a la API. Utilice la diferenciación de fotogramas: si la diferencia absoluta media entre fotogramas consecutivos supera un umbral, se ha producido un cambio de escena.

import cv2
import numpy as np

def extract_scene_change_frames(
    video_path: str,
    output_dir: str,
    diff_threshold: float = 30.0
) -> list:
    cap = cv2.VideoCapture(video_path)
    fps = cap.get(cv2.CAP_PROP_FPS)
    os.makedirs(output_dir, exist_ok=True)
    prev_gray = None
    saved = []
    frame_idx = 0

    while True:
        ret, frame = cap.read()
        if not ret:
            break
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        if prev_gray is not None:
            diff = np.mean(np.abs(gray.astype(float) - prev_gray.astype(float)))
            if diff > diff_threshold:
                ts = round(frame_idx / fps, 2)
                fname = f'{output_dir}/scene_{frame_idx:06d}_{ts}s.jpg'
                cv2.imwrite(fname, frame)
                saved.append({'path': fname, 'timestamp': ts, 'diff': round(diff, 2)})
        prev_gray = gray
        frame_idx += 1

    cap.release()
    return saved

Envío de una secuencia de fotogramas a la API de visión

Envíe varios fotogramas extraídos a la API de visión en un solo mensaje. Incluya la marca de tiempo de cada fotograma para que el modelo pueda razonar sobre el orden temporal y la duración. En el prompt, solicite explícitamente razonamiento temporal.

import base64
import anthropic

def describe_video_frames(frame_info_list: list, query: str) -> str:
    client = anthropic.Anthropic(api_key='YOUR_API_KEY')
    content = []
    for fi in frame_info_list:
        with open(fi['path'], 'rb') as f:
            b64 = base64.standard_b64encode(f.read()).decode('utf-8')
        content.append({
            'type': 'text',
            'text': f'Frame at {fi["timestamp"]}s:'
        })
        content.append({
            'type': 'image',
            'source': {'type': 'base64', 'media_type': 'image/jpeg', 'data': b64}
        })
    content.append({'type': 'text', 'text': query})

    response = client.messages.create(
        model='claude-opus-4-5',
        max_tokens=1024,
        messages=[{'role': 'user', 'content': content}]
    )
    return response.content[0].text

Prompts para el razonamiento temporal

El razonamiento temporal requiere formular el prompt de una manera específica. Pida al modelo que compare explícitamente los fotogramas, indique qué ha cambiado, estime la duración de las actividades e identifique las relaciones causales entre los fotogramas.

TEMPORAL_QUERY = (
    'You are analysing a video sequence. The frames above are in chronological order '
    'with their timestamps shown. Please:\n'
    '1. Describe what changed between the first and last frame\n'
    '2. Identify any notable events and when they occurred (timestamp)\n'
    '3. Summarise the overall activity shown in the video\n'
    '4. Estimate the total duration of the main activity\n'
    'Be specific about timestamps.'
)

# More targeted temporal query:
CHANGE_DETECTION_QUERY = (
    'Compare frame at {start_ts}s and frame at {end_ts}s. '
    'List all visible differences in bullet points. '
    'Categorise each change as: object_moved, object_added, '
    'object_removed, lighting_change, or camera_move.'
)

# Usage:
query = CHANGE_DETECTION_QUERY.format(start_ts=0.0, end_ts=20.0)

if __name__ == '__main__':
    print('Temporal reasoning query:')
    print(TEMPORAL_QUERY)
    print()
    print('Change detection query:')
    print(query)

Pipeline de resumen de vídeo

Un pipeline completo de resumen de vídeo consta de estos pasos: extraer fotogramas → enviarlos al modelo de visión en lotes → recopilar los resúmenes de cada lote → sintetizar el resumen final. El procesamiento por lotes evita superar el límite de la ventana de contexto.

def summarise_video(
    video_path: str,
    every_n_seconds: float = 10.0,
    batch_size: int = 5
) -> str:
    import anthropic
    client = anthropic.Anthropic(api_key='YOUR_API_KEY')

    # Extract frames
    frames = extract_frames(video_path, '/tmp/video_frames', every_n_seconds)

    # Process in batches
    batch_summaries = []
    for i in range(0, len(frames), batch_size):
        batch = frames[i:i + batch_size]
        ts_range = f'{batch[0]["timestamp"]}s - {batch[-1]["timestamp"]}s'
        query = f'Summarise what happens in this video segment ({ts_range}).'
        summary = describe_video_frames(batch, query)
        batch_summaries.append(f'[{ts_range}] {summary}')

    # Synthesise
    all_summaries = '\n\n'.join(batch_summaries)
    result = client.messages.create(
        model='claude-opus-4-5',
        max_tokens=512,
        messages=[{'role': 'user', 'content':
            f'Here are segment-level video summaries:\n\n{all_summaries}\n\n'
            'Write a single coherent summary of the entire video.'
        }]
    )
    return result.content[0].text

Seguimiento de objetos entre fotogramas

Pida al modelo de visión que siga objetos específicos a lo largo de una secuencia de fotogramas. Por ejemplo: 'En cada fotograma, describa la posición del coche rojo: arriba a la izquierda, arriba a la derecha, centro, abajo a la izquierda, abajo a la derecha.' Esto crea una trayectoria de movimiento aproximada sin utilizar algoritmos de seguimiento de visión artificial.

def track_object_across_frames(
    frames: list,
    object_description: str
) -> list:
    import anthropic, base64
    client = anthropic.Anthropic(api_key='YOUR_API_KEY')
    trajectory = []

    for fi in frames:
        with open(fi['path'], 'rb') as f:
            b64 = base64.standard_b64encode(f.read()).decode('utf-8')
        response = client.messages.create(
            model='claude-opus-4-5',
            max_tokens=128,
            messages=[{
                'role': 'user',
                'content': [
                    {'type': 'image', 'source': {'type': 'base64',
                      'media_type': 'image/jpeg', 'data': b64}},
                    {'type': 'text', 'text':
                      f'Where is the {object_description} in this frame? '
                      'Answer with one of: top-left, top-right, centre, '
                      'bottom-left, bottom-right, not-visible.'}
                ]
            }]
        )
        trajectory.append({
            'timestamp': fi['timestamp'],
            'position': response.content[0].text.strip()
        })
    return trajectory

Gestión de los límites de cantidad de fotogramas

Las ventanas de contexto de las API de visión limitan la cantidad de imágenes que se pueden enviar en cada solicitud (normalmente, entre 5 y 20 imágenes). Para vídeos largos, utilice un enfoque jerárquico: analice los segmentos de forma independiente y, después, combine sus resúmenes en un resumen final mediante una segunda llamada al LLM.

MAX_FRAMES_PER_REQUEST = 8

def hierarchical_video_analysis(frames: list, final_query: str) -> str:
    import anthropic
    client = anthropic.Anthropic(api_key='YOUR_API_KEY')

    # Level 1: analyse each chunk
    chunk_summaries = []
    for i in range(0, len(frames), MAX_FRAMES_PER_REQUEST):
        chunk = frames[i:i + MAX_FRAMES_PER_REQUEST]
        ts = f'{chunk[0]["timestamp"]}s-{chunk[-1]["timestamp"]}s'
        summary = describe_video_frames(
            chunk, f'What happens in this segment ({ts})?'
        )
        chunk_summaries.append(f'Segment {ts}: {summary}')

    # Level 2: synthesise all chunk summaries
    combined = '\n'.join(chunk_summaries)
    result = client.messages.create(
        model='claude-opus-4-5',
        max_tokens=512,
        messages=[{
            'role': 'user',
            'content': f'Video segments:\n{combined}\n\n{final_query}'
        }]
    )
    return result.content[0].text

Combinación del análisis de audio y vídeo

Para obtener una comprensión más completa, combine el análisis visual a nivel de fotograma con la transcripción de audio de Whisper. El agente puede relacionar lo que se ve con lo que se dice en cada marca de tiempo, lo que permite realizar tareas avanzadas como analizar reuniones o indexar tutoriales.

def full_video_analysis(video_path: str) -> dict:
    import subprocess

    # Step 1: Extract audio track
    audio_path = '/tmp/video_audio.mp3'
    subprocess.run([
        'ffmpeg', '-i', video_path, '-q:a', '0', '-map', 'a',
        audio_path, '-y'
    ], capture_output=True)

    # Step 2: Transcribe audio
    transcript_data = transcribe_with_timestamps(audio_path)

    # Step 3: Extract key frames
    frames = extract_frames(video_path, '/tmp/key_frames', every_n_seconds=15.0)

    # Step 4: Visual summary
    visual_summary = hierarchical_video_analysis(
        frames, 'Summarise the visual content.'
    )

    return {
        'transcript': transcript_data['full_text'],
        'transcript_segments': transcript_data['segments'],
        'visual_summary': visual_summary,
        'frame_count': len(frames)
    }

Limpieza y gestión de fotogramas

Los fotogramas extraídos pueden acumularse rápidamente. Limpie siempre los archivos temporales de fotogramas después del procesamiento e implemente una caché de fotogramas cuya clave sea el hash de (video_path, frame_rate) para evitar volver a extraerlos al analizar repetidamente el mismo vídeo.

import os
import shutil
import hashlib

FRAME_CACHE_DIR = '/tmp/frame_cache'

def get_cache_key(video_path: str, every_n_seconds: float) -> str:
    content = f'{video_path}:{every_n_seconds}'
    return hashlib.md5(content.encode()).hexdigest()[:12]

def get_or_extract_frames(video_path: str, every_n_seconds: float) -> list:
    key = get_cache_key(video_path, every_n_seconds)
    cache_dir = os.path.join(FRAME_CACHE_DIR, key)

    if os.path.exists(cache_dir):
        print(f'Cache hit: {key}')
        files = sorted(os.listdir(cache_dir))
        return [
            {'path': os.path.join(cache_dir, f),
             'timestamp': float(f.split('_')[-1].replace('s.jpg', ''))}
            for f in files if f.endswith('.jpg')
        ]
    return extract_frames(video_path, cache_dir, every_n_seconds)

def clear_frame_cache():
    if os.path.exists(FRAME_CACHE_DIR):
        shutil.rmtree(FRAME_CACHE_DIR)
        print('Frame cache cleared')

Comprobación de conocimientos

¿Por qué es preferible detectar los cambios de escena a realizar un muestreo uniforme de fotogramas para analizar vídeos?

Repaso: comprensión de vídeo en agentes

¡Buen trabajo! Estos son los puntos clave de la lección:

  • OpenCV: extraiga fotogramas con cap.read(); muestree cada N segundos o en los cambios de escena
  • Secuencias de fotogramas: envíelas en orden cronológico con marcas de tiempo para proporcionar contexto temporal
  • Análisis jerárquico: dividir en lotes → resúmenes de segmentos → síntesis final
  • Análisis combinado: ffmpeg extrae el audio; Whisper lo transcribe; después se contrasta con los fotogramas visuales
  • Caché de fotogramas: evite extracciones redundantes mediante un directorio de caché identificado por hash

Siguiente tema: razonamiento entre modalidades, cuando el texto dice una cosa y la imagen muestra otra.

Gratis para empezar

Aprende AI Agents con un tutor de IA — gratis

Escribe y ejecuta código real en tu navegador, obtén ayuda instantánea de un tutor de IA disponible 24/7 y continúa donde lo dejaste en la web o en la aplicación.

Cursos
60
Lecciones
239

Preguntas frecuentes

¿La lección «Comprensión de vídeo en agentes» es gratis?

Sí — el texto completo de «Comprensión de vídeo en agentes» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de AI Agents, actualiza a CoddyKit PRO. El curso de AI Agents incluye 4 lecciones en total.

¿Qué aprenderé en «Comprensión de vídeo en agentes»?

Extracción de fotogramas, resumen de vídeos y razonamiento temporal sobre clips. Practicas AI Agents con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar AI Agents?

No se requiere experiencia previa. AI Agents en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 3 de 4.

¿Cuánto tiempo toma la lección «Comprensión de vídeo en agentes»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de AI Agents?

Sí. Cada lección de AI Agents incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Agentes de imagen + texto con Claude Vision y GPT-4V
  2. Flujos de trabajo de agentes de audio + texto
  3. Comprensión de vídeo en agentes
  4. Patrones de razonamiento entre modalidades
← Volver a AI Agents