에이전트의 동영상 이해
프레임 추출, 동영상 요약, 클립의 시간적 추론을 다룹니다.
에이전트의 동영상 이해은(는) CoddyKit의 무료 AI Agents 강의입니다. 이것은 4개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 AI Agents 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. AI Agents 강의에는 총 4개의 강의가 포함되어 있습니다.
에이전트를 위한 비디오 이해
대부분의 LLM은 비디오 파일을 직접 처리할 수 없지만, 에이전트는 대표 프레임을 추출하여 이미지로 보내 비디오를 분석할 수 있습니다. 그러면 에이전트는 시각적 순서를 바탕으로 추론하여 시간에 따른 사건, 변화, 패턴을 감지합니다.
프레임 추출을 위한 OpenCV 설치
OpenCV(cv2)는 파이썬에서 비디오를 처리할 때 사용하는 표준 라이브러리입니다. 비디오 파일을 열고 메타데이터(프레임 속도, 해상도, 프레임 수)를 읽으며, 개별 프레임을 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)N초마다 프레임 추출
대부분의 비디오 이해 작업에서는 모든 프레임이 필요하지 않습니다. N초마다 프레임 하나를 샘플링하면 비디오 콘텐츠를 대표하는 요약을 얻을 수 있습니다. 초당 프레임 하나를 추출하면 60초 비디오에서 60개의 프레임이 생성됩니다.
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장면 전환 감지
일정한 간격으로 샘플링하는 대신 시각적 콘텐츠가 크게 바뀌는 순간인 장면 경계에서 프레임을 추출하십시오. 그러면 API 호출마다 더 유용한 프레임을 얻을 수 있습니다. 프레임 차분을 사용하여 연속된 프레임 사이의 평균 절대 차이가 임계값을 초과하면 장면이 전환된 것으로 판단합니다.
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비전 API로 프레임 순서 보내기
추출한 여러 프레임을 하나의 메시지로 비전 API에 보내십시오. 모델이 시간적 순서와 지속 시간을 추론할 수 있도록 각 프레임의 타임스탬프를 포함하십시오. 프롬프트에서 시간적 추론을 명시적으로 요청하십시오.
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시간적 추론 프롬프트
시간적 추론에는 구체적인 프롬프트 구성이 필요합니다. 모델에 프레임을 명시적으로 비교하고, 무엇이 바뀌었는지 기록하며, 활동의 지속 시간을 추정하고, 프레임 간 인과 관계를 식별하도록 요청하십시오.
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)
비디오 요약 처리 흐름
전체 비디오 요약 처리 흐름은 다음과 같습니다. 프레임 추출 → 비전 모델에 배치 단위로 전송 → 배치별 요약 수집 → 최종 요약 종합. 배치 처리를 사용하면 컨텍스트 창의 한도를 초과하는 것을 방지할 수 있습니다.
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프레임 간 객체 추적
비전 모델에 프레임 순서 전체에서 특정 객체를 추적하도록 요청하십시오. 예를 들어 '각 프레임에서 빨간 자동차의 위치를 설명하십시오: 왼쪽 위, 오른쪽 위, 중앙, 왼쪽 아래, 오른쪽 아래.'라고 요청할 수 있습니다. 이렇게 하면 컴퓨터 비전 추적 알고리즘 없이도 대략적인 움직임 궤적을 만들 수 있습니다.
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프레임 수 제한 처리
비전 API의 컨텍스트 창에는 요청 하나에 보낼 수 있는 이미지 수의 한도가 있습니다(일반적으로 이미지 5~20개). 긴 비디오에는 계층적 접근 방식을 사용하십시오. 구간을 독립적으로 분석한 다음, 두 번째 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오디오 및 비디오 분석 결합
가장 풍부한 이해를 얻으려면 프레임 단위의 시각적 분석과 위스퍼 오디오 텍스트 변환을 결합하십시오. 에이전트는 각 타임스탬프에서 보이는 것과 말한 것을 연관 지을 수 있으므로, 회의 분석이나 튜토리얼 색인과 같은 강력한 작업을 수행할 수 있습니다.
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)
}정리 및 프레임 관리
추출한 프레임은 빠르게 누적될 수 있습니다. 처리 후에는 항상 임시 프레임 파일을 정리하고, 동일한 비디오를 반복 분석할 때 다시 추출하지 않도록 비디오 경로와 프레임 속도의 해시를 키로 하는 프레임 캐시를 구현하십시오.
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')지식 확인
비디오 분석에서 일정한 간격의 프레임 샘플링보다 장면 전환 감지가 더 적합한 이유는 무엇입니까?
복습: 에이전트의 비디오 이해
잘하셨습니다! 이 수업의 핵심 내용은 다음과 같습니다.
- OpenCV:
cap.read()로 프레임을 추출하고, N초마다 또는 장면 전환 시 샘플링합니다. - 프레임 순서: 시간적 맥락을 위해 타임스탬프와 함께 시간순으로 보냅니다.
- 계층적 분석: 배치로 나누기 → 구간별 요약 → 최종 종합
- 결합 분석: ffmpeg로 오디오를 추출하고, 위스퍼로 텍스트를 변환한 다음 시각적 프레임과 대조합니다.
- 프레임 캐시: 해시를 키로 하는 캐시 디렉터리로 중복 추출을 방지합니다.
다음 주제: 교차 모달 추론 — 텍스트가 말하는 내용과 이미지가 보여 주는 내용이 다를 때입니다.
AI 튜터와 함께 AI Agents을(를) 배우세요 — 무료
브라우저에서 실제 코드를 작성하고 실행하며, 24/7 AI 튜터로부터 즉각적인 도움을 받고, 웹이나 앱에서 중단한 부분부터 계속 학습하세요.
- 코스
- 60
- 레슨
- 239
자주 묻는 질문
“에이전트의 동영상 이해” 강의는 무료인가요?
네 — “에이전트의 동영상 이해” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 AI Agents 강의 전체를 잠금 해제할 수 있습니다. AI Agents 강의에는 총 4개의 강의가 포함되어 있습니다.
“에이전트의 동영상 이해”에서 뭘 배우나요?
프레임 추출, 동영상 요약, 클립의 시간적 추론을 다룹니다. 브라우저에서 직접 실행하는 실습 코드로 AI Agents을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
AI Agents을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 AI Agents은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 3번째 강의입니다.
“에이전트의 동영상 이해” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 AI Agents 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 AI Agents 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.