Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
the script I used to average every episode of That 70's Show into a singe video
# first mount the samba share (use the gui)
# then link the mounted smb share somewhere more convientent
# sudo ln -s /run/user/1000/gvfs/smb-share:server=dlink-71f6dd,share=volume_1-1 /mnt/network
# then run as usual
# python /mnt/network/TV\ Shows/That\ \'70s\ Show/ output.avi
import os
import sys
import cv2
import numpy as np
#from multiprocessing.dummy import Pool
import time
from tqdm import *
import pdb
CODEC ='D','I','V','X')
class AvgEpisode(object):
def __init__(self, inputPath, outputPath):
self.inputPath = inputPath
self.outputPath = outputPath
# find all the files
self.files = self.all_files(self.inputPath)
# open all the files
self.episodes = [Episode(f, start_at=idx*30) for idx, f in enumerate(self.files)]
# set some basic parameters
self.width = 640
self.height = 480
self.fps = 24
self.length = self.episodes[0].length()
# create the output video
self.output = cv2.VideoWriter(self.outputPath,CODEC,self.fps,(self.width, self.height))
def start(self):
# create a progress bar
t = 1
for i in tqdm(range(self.length)):
# build the average frame
# write to output
# show the image
cv2.imshow("avg_frame", self.avg_frame)
key = 0xFF & cv2.waitKey(1)
if(key == 27): break
# inc t for progress bar
t = t + 1
def finish(self):
# close output
# close videos
for episode in self.episodes:
def all_files(self, path):
all_files = []
extensions = tuple(['jpg', 'db', 'txt'])
if os.path.exists(path):
for dirpath, dirnames, files in os.walk(path):
for name in files:
f = os.path.join(dirpath, name)
# reject some extensions
if not f.endswith(extensions):
#if(len(all_files) > 24): return all_files
#num_files = len(all_files)
#print 'found', num_files, 'files'
return all_files
print path, 'does not exist'
def build_avg_frame(self):
# init the average frame as zeros
self.avg_frame = np.zeros((self.height, self.width, 3), dtype=np.float64)
# add all the frames together
self.frames_read = 0
for idx, episode in enumerate(self.episodes):
frame = episode.read_frame()
if(frame == None): continue
self.add_frame(frame, episode.filename)
# pool_size = 8
# pool = Pool(pool_size)
# for episodes in batch(self.episodes, pool_size):
# frames =, episodes)
# # join processes and add the frame
# for idx, frame in enumerate(frames):
# if(frame == None): continue
# self.add_frame(frame, episodes[idx].filename)
# divide by the number of frames_read to average
self.avg_frame = np.divide(self.avg_frame, self.frames_read)
# normalize the avg frame
self.avg_frame = cv2.normalize(self.avg_frame, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX).astype(np.uint8)
def add_frame(self, frame, file_name):
frame = frame.astype(np.float64)
frame = cv2.resize(frame, (self.width, self.height))
self.avg_frame = np.add(self.avg_frame, frame)
self.frames_read += 1
print file_name, ' add failed', sys.exc_info()[0]
class Episode:
def __init__(self, filename, start_at=0):
self.filename = filename
self.cap = cv2.VideoCapture(self.filename)
self.start_at = start_at
self.frame_count = 0
self.finished = False
def length(self):
return int(self.cap.get(
def read_frame(self):
if(self.finished == True): return
frame = self._read()
self.frame_count += 1
if(self.frame_count < self.start_at): return
return frame
print self.filename, '.read() crashed', sys.exc_info()[0]
def _read(self):
flag, frame =
if(flag == False):
print self.filename, '.read() failed'
self.finished = True
return frame
def release(self):
# # iterate in batches (for passing to threads)
# def batch(iterable, n=1):
# l = len(iterable)
# for ndx in range(0, l, n):
# yield iterable[ndx:min(ndx + n, l)]
# # read frame from a thread
# def thread_read_frame(episode):
# return episode.read_frame()
if __name__ == "__main__":
inputPath = sys.argv[1]
outputPath = sys.argv[2]
AvgEpisode(inputPath, outputPath).start()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.