반응형
영상 프레임 보간 AI인 RIFE를 파이썬에서 사용하는 방법입니다.
프레임 사이사이에 AI가 중간 프레임을 생성해주기 때문에 슬로우 모션을 걸어도 끊기지 않습니다.
RIFE 다운로드
두 가지 방식이 있습니다.
1. CUDA/PyTorch (NVIDIA GPU)
pip install torch torchvision pillow
모델 파일은 RIFE GitHub에서 받을 수 있습니다.
train_log 폴더에 RIFE_HDv3.py와 체크포인트 파일이 필요합니다.
2. ncnn-vulkan (AMD 등 모든 GPU)
rife-ncnn-vulkan releases에서 exe 파일을 받으면 됩니다.
별도 파이썬 패키지 설치 없이 subprocess로 호출하는 방식입니다.
1단계: FFmpeg로 프레임 추출
먼저 영상을 JPG 프레임으로 쪼갭니다.
import subprocess
FFMPEG = 'ffmpeg.exe 경로'
subprocess.run([
FFMPEG, '-y',
'-hwaccel', 'cuda',
'-i', '입력영상.mp4',
'-qscale:v', '2',
'temp/in/%08d.jpg'
])
-hwaccel cuda는 GPU 디코딩 가속 옵션입니다. 없어도 동작하지만 속도 차이가 꽤 납니다.
-qscale:v 2는 JPG 품질 설정으로 낮을수록 고품질입니다.
2단계: RIFE 프레임 보간
CUDA 방식
import torch
from torchvision import transforms
from PIL import Image
from train_log.RIFE_HDv3 import Model
# 모델 로드 (최초 1회)
model = Model()
model.load_model('rife_model/train_log', -1)
model.eval()
model.device()
torch.set_grad_enabled(False)
# 프레임 보간
frames = sorted(Path('temp/in').glob('*.jpg'))
multiply = 8 # 프레임 8배
idx = 0
for i in range(len(frames) - 1):
img0 = transforms.ToTensor()(Image.open(frames[i])).unsqueeze(0).cuda().half()
img1 = transforms.ToTensor()(Image.open(frames[i+1])).unsqueeze(0).cuda().half()
# 원본 프레임 저장
Image.open(frames[i]).save(f'temp/out/{idx:08d}.jpg', quality=95)
idx += 1
# 중간 프레임 생성
for ti in range(1, multiply):
t = ti / multiply
mid = model.inference(img0, img1, t)
transforms.ToPILImage()(mid.squeeze(0).float().clamp(0,1).cpu()) \
.save(f'temp/out/{idx:08d}.jpg', quality=95)
idx += 1
핵심은 model.inference(img0, img1, t) 한 줄입니다. t값(0~1)에 따라 두 프레임 사이 원하는 위치의 중간 프레임을 생성해줍니다.
ncnn-vulkan 방식
RIFE_NCNN = 'rife-ncnn-vulkan.exe 경로'
MODEL_PATH = 'rife-v4.6 모델 폴더'
frame_count = len(list(Path('temp/in').glob('*.jpg')))
target = frame_count * 8 # 8배 보간
subprocess.run([
RIFE_NCNN,
'-i', 'temp/in',
'-o', 'temp/out',
'-n', str(target),
'-m', MODEL_PATH,
'-g', '0', # GPU 번호
'-j', '8:8:8', # 스레드 수
'-f', '%08d.jpg'
])
exe 파일 하나로 끝나서 환경 세팅이 훨씬 간단합니다.
3단계: FFmpeg로 슬로우 모션 인코딩
original_fps = 30
multiply = 8
slow_factor = 2
output_fps = original_fps * multiply / slow_factor # 120fps
subprocess.run([
FFMPEG, '-y',
'-framerate', str(output_fps),
'-start_number', '0',
'-i', 'temp/out/%08d.jpg',
'-an',
'-c:v', 'libx264',
'-crf', '23',
'-preset', 'veryslow',
'-pix_fmt', 'yuv420p',
'-movflags', '+faststart',
'output/result_rife8x_slow2x.mp4'
])
출력 FPS 계산이 포인트입니다. 30fps 원본을 8배 보간하면 240fps 분량의 프레임이 생기는데, 이걸 120fps로 재생하면 2배 슬로우가 됩니다.
주의사항
- 장면 전환(컷)이 있는 구간은 프레임이 깨집니다
- 원본 FPS가 높을수록 결과가 좋습니다
- 배수가 높을수록 처리 시간이 비례해서 늘어납니다
반응형