검색
검색
공개 노트 검색
회원가입로그인

GPT-4 Vision으로 동영상 분석해서 설명 만들기

현재 GPT-4 Vision은 동영상을 입력값으로 직접 처리하지는 않습니다. 하지만 비전의 이미지 분석 능력과 128k 컨텍스트를 사용해 동영상의 프레임을 모두 집어넣고 이에 대한 설명을 생성할 수 있습니다. 이는 OpenAI의 Cookbook에 작성된 코드를 기반으로 합니다.

Processing and narrating a video with GPT's visual capabilities and the TTS API | OpenAI Cookbook

코드 만들기

먼저 vision 이라는 폴더를 만들고 vision-video.py 라는 파일을 만들겠습니다. 그리고 다음과 같이 코드를 작성합니다.

import cv2  
# 비디오를 읽기 위해 OpenCV 를 사용합니다. 설치하려면 다음 명령어를 입력하세요.
# !pip install opencv-python
import base64
from openai import OpenAI

# 여러분의 키를 입력해 주세요.
client = OpenAI(api_key='YOUR_OPEN_API_KEY')

video = cv2.VideoCapture("data/bison.mp4")

bison.mp4 동영상 파일은 여기에서 다운로드 받을 수 있습니다. openai-cookbook/examples/data at main · openai/openai-cookbook 들소와 늑대가 눈 내린 장면에 나오는 샘플 비디오입니다.

base64Frames = []
while video.isOpened():
    success, frame = video.read()
    if not success:
        break
    _, buffer = cv2.imencode(".jpg", frame)
    base64Frames.append(base64.b64encode(buffer).decode("utf-8"))

video.release()
print(len(base64Frames), "frames read.")

이제 동영상을 읽이 위해서 open cv를 활용해 보겠습니다. 동영상을 읽어 각 프레임별로 base64 인코딩 문자열로 저장합니다.

Base64는 바이너리 데이터를 64개의 인쇄 가능한 ASCII 문자로만 이루어진 텍스트로 변환하는 인코딩 방식입니다. 주로 이메일이나 데이터 URL 등 텍스트만을 취급하는 매체에 바이너리 데이터를 임베딩할 때 사용됩니다. 이미지와 같은 바이너리 데이터를 텍스트로 만들어 취급할 수 있습니다.

예시

3wKD4K0thjyVH/ABXOf8NL/DluVt7rnoNn/1qUftG+CJOFsLjHr/AJFCi0aRmmatz4G0xWysIOfRR/hXE+MfhIl7vmhiDqx+6RzXTQ/GrwXefOfMQZ/5aDFJP8VPBM3S9C/jTd7FXR5BrXhK28L2rWT2fkrJ1GMA1yfjj4GTjQR4hNgwWTkmPqPc1638XtY8GeLfDL2tpqLJOHzHKse7jHIxkdePyrhtT+Jtz/wiK+FrhDMyIF+0FsE8Y6f/AF65He4KStueSeEdVb/hD9H+b/mE23f/AKZLWjHqYZck9uOa5vwi/wDxR+j/AD/8wm27/wDTJa0Yn4+929a95p3R5l2aJ1EZ6fmaBqKk4x+tZpc55b9aUSYOd361qBpm8GODn8Kja9P8P61SNxgfeqNrg+tAF77S3qfypDctg8n8qo/afej7T70AWGuW3cn86abgkYP8qh+0D1P50faB6n86Dlbdybzj70ecfeq3m+5oEvPU0CuyUSMTgA/lTlLd8/lR5qetHmp61aijckdxtPBqAy8nk0eb7mo/N9zRZASeZ9aTePQ0zzfc0eb7miyAdvb1o3t61X89fQ0eenoaZzlje3rSMzYPNQeenoaPPT0NAEMrt5h5pu9vWkoreyAXe3rRvb1qelT7wosgDL/5FKrPu/8ArVIEBGaUIAc0WQEgAxyKWpBwMUVgBHRUlFABRRRQBHRUlFTygFFFFUAUUUUASUUUUAFFFFAEdMAycVPRSauBF5XsaPK9jUtFLlAb5fvR5fvTaKkB3me1Hme1Jsb0oCHPNAD6koWBmGRzU32Ye/50ALsT+6PyqXA9Kh+yj1P51MIiDnFAD9g9TQEANIHwMYo8z2oAXyvY0CLJxzR5z

이런식으로 수 많은 문자가 나옵니다. 이를 html 의 이미지 요소 등에 바로 올려서 사용할 수 있습니다.

여기까지 하고 실행해 보겠습니다.

python vision-video.py

618 frames read.

21초짜리 동영상이 618 프레임이 나왔군요. 초당 약 30 프레임 정도네요.

이제 이걸 vision으로 보내 보겠습니다.

PROMPT_MESSAGES = [
    {
        "role": "user",
        "content": [
            "These are frames from a video that I want to upload. Generate a compelling description that I can upload along with the video.",
            *map(lambda x: {"image": x, "resize": 768}, base64Frames[0::50]),
        ],
    },
]
params = {
    "model": "gpt-4-vision-preview",
    "messages": PROMPT_MESSAGES,
    "max_tokens": 200,
}
# print(PROMPT_MESSAGES)
result = client.chat.completions.create(**params)
print(result.choices[0].message.content)  

*map(lambda x: {"image": x, "resize": 768}, base64Frames[0::50]),

prompt message를 보면 파이썬의 map 함수를 통해 익명함수인 lambda를 활용해 이미지의 x 에 base64 인코딩을 넣고 사이즈를 768로 정해서 개별적으로 만드는 것(*)을 알 수 있습니다. 프레임은 50개씩 끊어서 처리하네요.

람다란 이름이 없는 익명함수라는 뜻으로 다음과 같이 사용합니다.

lambda 인자: 표현식

왼쪽에 인자가 들어가서 표현식에서 사용됩니다. 우리의 예시는 x 라는 인자를 받아 {"image": x, "resize": 768} 와 같은 딕셔너리를 만들어 내고 있습니다.

result = client.chat.completions.create(**params)

**params는 Python에서 '키워드 인자 패킹'을 사용한 것입니다. 이는 params 딕셔너리의 각 키-값 쌍을 함수의 키워드 인자로 전달합니다. 즉, 위의 딕셔너리를 사용하여 함수를 호출하면 다음과 같이 해석됩니다:

result = client.chat.completions.create(model="gpt-4-vision-preview", messages=PROMPT_MESSAGES, max_tokens=200)

max_tokens은 출력시 생성할 수 있는 최대 토큰을 의미합니다. 이제 코드를 실행해 봅시다.

python vision-video.py

Title: "The Struggle for Survival: A Pack of Wolves Hunting Bison in the Snowy Wilderness"

Description:
Immerse yourself in the raw beauty and drama of nature with this gripping video showcasing the intense struggle for survival in the heart of the snowy wilderness. Watch in awe as a determined pack of wolves works together to hunt a bison, employing their strategic skills and pack dynamics against the formidable strength and size of their prey. Each frame captures the brutal dance between predator and prey, with the stark white landscape providing a fitting backdrop to this ultimate test of survival. Witness the power of the wild unfold; will the wolves' tenacity and teamwork secure them a meal, or will the bison's raw power lead to its escape? Join us on this thrilling journey into the lives of these majestic creatures and see nature's drama at its most primal. Don't forget to like, share, and subscribe for more breathtaking wildlife content!

한글

제목 : 적자 생존 : 한 무리의 늑대가 눈 내린 야생에서 들소를 사냥하다. 

설명:
눈 덮인 황야 한가운데서 생존을 위한 치열한 투쟁을 보여주는 이 흥미진진한 영상을 통해 자연의 생생한 아름다움과 드라마에 빠져보세요. 결의에 찬 늑대 무리가 함께 협력하여 들소를 사냥하는 모습을 지켜보세요. 전략적 기술과 무리의 역동성을 활용하여 먹이의 엄청난 힘과 크기에 맞서 싸우는 모습을 지켜보세요. 각 프레임은 포식자와 먹이 사이의 잔혹한 춤을 포착하며, 순백의 풍경은 이 궁극적인 생존 시험에 적합한 배경을 제공합니다. 야생의 힘이 펼쳐지는 것을 목격하세요. 늑대의 끈기와 팀워크가 그들에게 식사를 제공할 것인가, 아니면 들소의 순수한 힘이 탈출로 이어질 것인가? 이 장엄한 생물들의 삶 속으로 들어가는 스릴 넘치는 여행에 참여하여 가장 원시적인 자연의 드라마를 감상하세요. 더 많은 숨막히는 야생동물 콘텐츠를 보려면 좋아요, 공유, 구독하는 것을 잊지 마세요!

동영상을 잘 설명해주는 것이 보이시나요? 자연 다큐멘터리 소개처럼 잘 소개해 주었네요. 그런데 마지막에 '좋아요, 공유, 구독을 잊지마세요'는 뭘까요...이런것도 배우나 봐요 ㅋㅋㅋ

마지막으로 전체 코드입니다.

import cv2  # We're using OpenCV to read video, to install !pip install opencv-python
import base64
from openai import OpenAI

# 여러분의 키를 입력해 주세요.
client = OpenAI(api_key='YOUR_OPEN_API_KEY')

video = cv2.VideoCapture("data/bison.mp4")

base64Frames = []
while video.isOpened():
    success, frame = video.read()
    if not success:
        break
    _, buffer = cv2.imencode(".jpg", frame)
    base64Frames.append(base64.b64encode(buffer).decode("utf-8"))

video.release()
print(len(base64Frames), "frames read.")

PROMPT_MESSAGES = [
    {
        "role": "user",
        "content": [
            "These are frames from a video that I want to upload. Generate a compelling description that I can upload along with the video.",
            *map(lambda x: {"image": x, "resize": 768}, base64Frames[0::50]),
        ],
    },
]
params = {
    "model": "gpt-4-vision-preview",
    "messages": PROMPT_MESSAGES,
    "max_tokens": 200,
}
# print(PROMPT_MESSAGES)
result = client.chat.completions.create(**params)
print(result.choices[0].message.content)
조회수 : 1107
heart
공유하기
카카오로 공유하기
페이스북 공유하기
트위터로 공유하기
url 복사하기
T
페이지 기반 대답
AI Chat