Skip to content

Instantly share code, notes, and snippets.

@Frencil
Created April 1, 2015 03:15
Show Gist options
  • Save Frencil/7f6cd3007c9c1bb1429a to your computer and use it in GitHub Desktop.
Save Frencil/7f6cd3007c9c1bb1429a to your computer and use it in GitHub Desktop.
Python video stacker
import os, sys, numpy, PIL
from PIL import Image
# Build list of source video clips from arguments
clips = []
for i in range(1,len(sys.argv),2):
path = sys.argv[i]
offset = sys.argv[i+1]
filename, ext = path.split('.')
clip = { 'path': path,
'offset': int(offset),
'name': filename,
'frames': [],
}
clips.append(clip)
min_frame_count = None
max_frame_count = None
for clip in clips:
# Process clip to frames
print('[STACK] Splitting ' + clip['name'] + ' into frames...')
try:
os.mkdir(clip['name'])
ffmpeg_cmd = 'ffmpeg -i ' + clip['path'] + ' -s hd720 -qscale:v 2 ' + clip['name'] + '/image%05d.jpg'
os.system(ffmpeg_cmd)
except OSError:
print("[STACK] " + clip['name'] + " already processed to frames; skipping processing step.")
# Load frame files to clip object
frames = os.listdir(clip['name'])
clip['frames'] = sorted([filename for filename in frames if filename[-4:] in [".jpg"]])
# Track min and max frame counts
frame_count = len(clip['frames']) + clip['offset']
if (min_frame_count == None):
min_frame_count = frame_count
else:
min_frame_count = min(min_frame_count, frame_count)
if (max_frame_count == None):
max_frame_count = frame_count
else:
max_frame_count = max(max_frame_count, frame_count)
print("[STACK] min_frame_count: " + str(min_frame_count))
print("[STACK] max_frame_count: " + str(max_frame_count))
# Prepare output directory for composite frames
os.mkdir('composite')
# Advance through frames across clips to build and export composite frames
print("[STACK] Generating composite video frames: ")
step = max_frame_count / 10
for f in range(0,max_frame_count):
composite = numpy.zeros((720,1280,3),numpy.float)
divisor = 0
for clip in clips:
frame_index = f - clip['offset']
if 0 <= frame_index < len(clip['frames']):
frame_path = clip['name'] + '/' + clip['frames'][frame_index]
clip_frame = numpy.array(Image.open(frame_path), dtype=numpy.float)
composite += clip_frame
divisor += 1
if divisor > 0:
composite /= divisor
# Round values in array and cast as 8-bit integer
composite = numpy.array(numpy.round(composite), dtype=numpy.uint8)
# Generate the composite frame
frame = Image.fromarray(composite, mode="RGB")
frame_path = 'composite/%05d.jpg' % f
frame.save(frame_path)
# Update progress output
if (f % step == 0):
print '\b.',
sys.stdout.flush()
# Combine composite frames into video
print("[STACK] Generating composite video file...")
os.chdir('composite')
os.system('ls -1tr > frames.txt')
mencoder_cmd = 'mencoder -nosound -ovc lavc -lavcopts vcodec=mpeg4:mbd=2:trell:autoaspect:vqscale=3:threads=4 -vf scale=1280:720 -mf type=jpeg:fps=30 mf://@frames.txt -o ../composite.mov'
os.system(mencoder_cmd)
os.chdir('../')
# Clean everything up
print("[STACK] Cleaning up...")
for clip in clips:
os.system('rm -r ' + clip['name'])
os.system('rm -r composite')
print("[STACK] Done.")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment