Skip to content

Instantly share code, notes, and snippets.

@alexjercan
Created August 16, 2021 17:03
Show Gist options
  • Save alexjercan/2b0dceaaf61923d80be3018178255873 to your computer and use it in GitHub Desktop.
Save alexjercan/2b0dceaaf61923d80be3018178255873 to your computer and use it in GitHub Desktop.
Python script that uses the Blender Video Editor to automate image sequence plus audio into video file
import os
import re
import sys
import bpy
import argparse
from pathlib import Path
def atoi(text):
return int(text) if text.isdigit() else text
def natural_keys(paths):
return [ atoi(c) for c in re.split(r'(\d+)', str(paths)) ]
def image_strip_add(sequence_editor, files):
filepath, filename = str(files[0]), files[0].name
imstrip = sequence_editor.sequences.new_image(filename, filepath=filepath, channel=1, frame_start=0)
for file in files[1:]:
imstrip.elements.append(file.name)
imstrip.frame_final_duration = len(files)
imstrip.update()
def sound_strip_add(sequence_editor, file):
sequence_editor.sequences.new_sound(file, filepath=file, channel=1, frame_start=0)
if __name__ == "__main__":
AUDIO_DEFAULT_PATH = os.path.abspath(os.path.join("..", "resources", "Sigma Male Theme Song.mp3"))
IMAGES_DEFAULT_ROOT_PATH = os.path.abspath(os.path.join("..", "yt-comments-to-pngs", "out"))
OUTPUT_DEFAULT_ROOT_PATH = os.path.abspath(os.path.join("..", "out"))
parser = argparse.ArgumentParser(description='Generate video with bpy editor')
parser.add_argument("--audio", type=str, default=AUDIO_DEFAULT_PATH, help="Path to music file")
parser.add_argument("--imgs_dir", type=str, default=IMAGES_DEFAULT_ROOT_PATH, help="Path to images root dir")
parser.add_argument("--out_dir", type=str, default=OUTPUT_DEFAULT_ROOT_PATH, help="Path to output root dir")
args = sys.argv[sys.argv.index("--") + 1:]
args = parser.parse_args(args)
print(args)
## SCENE SETUP ##
bpy.context.scene.view_settings.view_transform = 'Standard'
bpy.context.scene.frame_start = 0
bpy.context.scene.frame_end = 34
bpy.context.scene.frame_step = 1
bpy.context.scene.render.fps = 1
bpy.context.scene.render.fps_base = 8
bpy.context.scene.render.image_settings.file_format = 'FFMPEG'
bpy.context.scene.render.ffmpeg.constant_rate_factor = 'PERC_LOSSLESS'
bpy.context.scene.render.ffmpeg.ffmpeg_preset = 'BEST'
bpy.context.scene.render.ffmpeg.gopsize = 1
bpy.context.scene.render.ffmpeg.audio_codec = 'MP3'
## Load images ##
image_filepaths = list(sorted(Path(args.imgs_dir).glob("*.png"), key=natural_keys))
n_images = len(image_filepaths)
frame_step = 35
for index, frame_start in enumerate(range(0, n_images, frame_step)):
bpy.context.scene.render.filepath = os.path.join(args.out_dir, "part%d_" % index)
## Create editor ##
bpy.context.scene.sequence_editor_clear()
sequence_editor = bpy.context.scene.sequence_editor_create()
## Load audio ##
sound_strip_add(sequence_editor, args.audio)
current_filepaths = image_filepaths[frame_start:frame_start+frame_step]
image_strip_add(sequence_editor, current_filepaths)
## Render ##
bpy.ops.render.render(animation=True)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment