0Pricing
AI Agents · Pelajaran

Pemahaman Video dalam Agen

Ekstraksi bingkai, peringkasan video, dan penalaran temporal pada klip.

Pemahaman Video dalam Agen adalah pelajaran AI Agents gratis di CoddyKit. Ini adalah pelajaran 3 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar AI Agents, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus AI Agents mencakup 4 pelajaran total.

Pemahaman Video untuk Agen

Sebagian besar LLM tidak dapat memproses berkas video secara langsung, tetapi agen dapat menganalisis video dengan mengekstrak bingkai yang representatif dan mengirimkannya sebagai gambar. Agen kemudian melakukan penalaran terhadap urutan visual tersebut untuk mendeteksi peristiwa, perubahan, dan pola dari waktu ke waktu.

Memasang OpenCV untuk Ekstraksi Bingkai

OpenCV (cv2) adalah pustaka standar untuk pemrosesan video dalam Python. Pustaka ini memungkinkan Anda membuka berkas video, membaca metadatanya (laju bingkai, resolusi, jumlah bingkai), dan mengekstrak setiap bingkai sebagai larik 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)

Mengekstrak Bingkai Setiap N Detik

Untuk sebagian besar tugas pemahaman video, Anda tidak memerlukan setiap bingkai. Mengambil sampel satu bingkai setiap N detik memberikan ringkasan yang representatif tentang isi video. Pada laju 1 bingkai per detik, video berdurasi 60 detik menghasilkan 60 bingkai.

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

Deteksi Perubahan Adegan

Alih-alih mengambil sampel secara seragam, ekstrak bingkai pada batas adegan — momen ketika isi visual berubah secara signifikan. Cara ini menghasilkan bingkai yang lebih informatif untuk setiap panggilan API. Gunakan perbandingan selisih bingkai: jika perbedaan absolut rata-rata antara bingkai yang berurutan melebihi ambang batas, berarti terjadi perubahan adegan.

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

Mengirim Urutan Bingkai ke API Visi

Kirim beberapa bingkai yang diekstrak ke API visi dalam satu pesan. Sertakan stempel waktu setiap bingkai agar model dapat menalar urutan waktu dan durasinya. Minta secara eksplisit penalaran temporal dalam instruksi Anda.

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

Instruksi Penalaran Temporal

Penalaran temporal memerlukan perumusan instruksi yang spesifik. Minta model membandingkan bingkai secara eksplisit, mencatat perubahan, memperkirakan durasi aktivitas, dan mengidentifikasi hubungan sebab-akibat antarb bingkai.

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)

Alur Pemrosesan Ringkasan Video

Alur pemrosesan ringkasan video yang lengkap: ekstrak bingkai → kirim ke model visi dalam beberapa kelompok → kumpulkan ringkasan setiap kelompok → susun ringkasan akhir. Pengelompokan mencegah terlampauinya batas jendela konteks.

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

Melacak Objek Antarbingkai

Minta model visi melacak objek tertentu di seluruh urutan bingkai. Contohnya: 'Pada setiap bingkai, jelaskan posisi mobil merah: kiri atas, kanan atas, tengah, kiri bawah, kanan bawah.' Cara ini membuat lintasan gerak kasar tanpa algoritme pelacakan visi komputer.

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

Menangani Batas Jumlah Bingkai

Jendela konteks API visi memiliki batas jumlah gambar yang dapat dikirim dalam satu permintaan (biasanya 5–20 gambar). Untuk video panjang, gunakan pendekatan hierarkis: analisis setiap segmen secara terpisah, lalu gabungkan ringkasan segmen menjadi ringkasan akhir menggunakan panggilan LLM kedua.

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

Menggabungkan Analisis Audio dan Video

Untuk pemahaman yang paling menyeluruh, gabungkan analisis visual tingkat bingkai dengan transkripsi audio Whisper. Agen dapat menghubungkan apa yang dilihat dengan apa yang dikatakan pada setiap stempel waktu, sehingga memungkinkan tugas yang bermanfaat seperti analisis rapat atau pengindeksan tutorial.

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)
    }

Pembersihan dan Pengelolaan Bingkai

Bingkai yang diekstrak dapat cepat menumpuk. Selalu bersihkan berkas bingkai sementara setelah pemrosesan, dan terapkan tembolok bingkai dengan kunci berdasarkan nilai pencincangan dari (jalur video, laju bingkai) untuk menghindari ekstraksi ulang saat video yang sama dianalisis berulang kali.

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')

Uji Pemahaman

Mengapa deteksi perubahan adegan lebih baik daripada pengambilan sampel bingkai secara seragam untuk analisis video?

Ringkasan: Pemahaman Video dalam Agen

Kerja bagus! Poin-poin penting dari pelajaran ini:

  • OpenCV: ekstrak bingkai dengan cap.read(); ambil sampel setiap N detik atau saat terjadi perubahan adegan
  • Urutan bingkai: kirim dalam urutan kronologis dengan stempel waktu untuk memberikan konteks temporal
  • Analisis hierarkis: bagi menjadi beberapa kelompok → ringkasan segmen → sintesis akhir
  • Analisis gabungan: ffmpeg mengekstrak audio; Whisper mentranskripsikannya; lakukan rujuk silang dengan bingkai visual
  • Tembolok bingkai: hindari ekstraksi berulang dengan direktori tembolok yang menggunakan kunci hash

Berikutnya: penalaran lintas modalitas — ketika teks menyatakan satu hal, tetapi gambar menunjukkan hal lain.

Pertanyaan yang Sering Diajukan

Apakah pelajaran “Pemahaman Video dalam Agen” gratis?

Ya — teks lengkap “Pemahaman Video dalam Agen” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus AI Agents, upgrade ke CoddyKit PRO. Kursus AI Agents mencakup 4 pelajaran total.

Apa yang akan aku pelajari di “Pemahaman Video dalam Agen”?

Ekstraksi bingkai, peringkasan video, dan penalaran temporal pada klip. Kamu berlatih AI Agents dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.

Apakah aku perlu pengalaman untuk memulai AI Agents?

Tidak diperlukan pengalaman sebelumnya. AI Agents di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 3 dari 4.

Berapa lama pelajaran “Pemahaman Video dalam Agen” memakan waktu?

Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.

Bisakah aku menulis dan menjalankan kode dalam pelajaran AI Agents ini?

Ya. Setiap pelajaran AI Agents menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.

Semua pelajaran dalam kursus ini

  1. Agen Gambar + Teks dengan Claude Vision dan GPT-4V
  2. Alur Kerja Agen Audio + Teks
  3. Pemahaman Video dalam Agen
  4. Pola Penalaran Lintas Modalitas
← Kembali ke AI Agents