Skip to content

Instantly share code, notes, and snippets.

@patmandenver
Last active April 1, 2018 04:14
Show Gist options
  • Select an option

  • Save patmandenver/29c8652c267d5063f9434b6560f15232 to your computer and use it in GitHub Desktop.

Select an option

Save patmandenver/29c8652c267d5063f9434b6560f15232 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
#
# Script to help create time-lapse videos
#
##################################################
import argparse
import sys, os
import datetime
from shutil import copyfile
import time
image_types = ('.png', '.jpg', '.jpeg')
def parseArgs():
parser = argparse.ArgumentParser()
parser.add_argument("-f", "--folder", action='store', dest='images_folder', help="Folder that contains all images and subfolders you want to create videos for", required=False, default=None)
parser.add_argument("-r", "--recreate-videos", action='store', dest='recreate_videos', help="Recreates videos otherwise if they exist they will be skipped", required=False, default=False)
parser.add_argument("-v", "--verbose", action='store', dest='verbose', help="Allows ffmpeg to be verbose", required=False, default=False)
parser.add_argument("-t", "--test", action='store', dest='test', help="Test creates a 10 second video", required=False, default=False)
parser.add_argument("-c", "--crop", action='store', dest='crop', help="Crop and zoom", required=False, default="")
parser.add_argument("-x", "--x-speed", action='store', dest='x_speed', help="speed multiplier", required=False, default=1)
return parser.parse_args()
def get_folders_with_images(img_folder, file_extension):
folders_with_images = []
all_folders = [x[0] for x in os.walk(img_folder)]
for folder in all_folders:
for file_name in os.listdir(folder):
if file_name.lower().endswith(image_types):
folders_with_images.append(folder)
break
return folders_with_images
def get_start_number(folder):
start_num = -1
for file_name in os.listdir(folder):
if file_name.lower().endswith(image_types):
number = file_name[1:file_name.rfind(".")]
if start_num == -1 or start_num > int(number):
start_num = int(number)
return start_num
def print_elapsed_time(start_time, end_time):
elapsed_time = end_time - start_time
days = int(elapsed_time.seconds / (3600*24))
hours = int((elapsed_time.seconds - days*3600*24)/3600)
minutes = int((elapsed_time.seconds - days*3600*24 - hours*3600)/60)
seconds = int((elapsed_time.seconds - days*3600*24 - hours*3600 - minutes*60))
print(elapsed_time.seconds)
print(str(days) + " days " + str(hours) + " hours " + str(minutes) + " min " + str(seconds) + " sec")
#This will fill in gaps it finds in file numbers
def fill_in_gaps(folder, start_num):
last_img_file = "G" + str(start_num).zfill(7) + ".JPG"
file_list = os.listdir(folder)
biggest_num = start_num
#Find biggest file Number
for file_name in file_list:
if file_name.lower().endswith(image_types):
temp_num = int(file_name[1:-4])
if temp_num > biggest_num:
biggest_num = temp_num
#Check sequence
for x in range(start_num, biggest_num):
file_check_name = "G" + str(x).zfill(7) + ".JPG"
if not os.path.exists(folder + "/" + file_check_name):
prior_file = "G" + str(x-1).zfill(7) + ".JPG"
print("Missing sequential file !!!!\n copying prior file \n'" + folder + "/" + prior_file + "' to\n'" + folder + "/" + file_check_name + "'")
copyfile(folder + "/" + prior_file,folder + "/" + file_check_name)
time.sleep(1)
################################################################################
# MAIN
################################################################################
if __name__ == '__main__':
args = parseArgs()
img_folder = args.images_folder
recreate = args.recreate_videos
verbose = args.verbose
test = args.test
crop = args.crop
x_speed = args.x_speed
if img_folder is None:
img_folder = os.getcwd()
print("No image folder given using current director '" + str(img_folder) + "'")
#Start timer
start_time = datetime.datetime.now()
#check if folder exists
if os.path.exists(img_folder):
folders_with_images = get_folders_with_images(img_folder, ".JPG")
print(" === Obtaining all folders with image data ===")
x = 0
for folder in folders_with_images:
x += 1
print(" === working on " + str(x) + "/" + str(len(folders_with_images)) + " === ")
if x_speed > 1:
video_name = img_folder[img_folder.rfind('/')+1:] + folder[len(img_folder):].replace("/", "_") + "_" + str(x_speed) + "x.mp4"
else:
video_name = img_folder[img_folder.rfind('/')+1:] + folder[len(img_folder):].replace("/", "_") + ".mp4"
#if exists and recreate:
if os.path.isfile(img_folder + "/" + video_name) and not recreate:
print("video file exists '" + str(video_name) + "' ... Skipping creation")
#Want to skip
continue
#Find start number of files!
start_number = get_start_number(folder)
#Use ffmpeg on the command line to create video
#Had to do some funky stuff since it is using the windows ffmpeg
individual_start_time = datetime.datetime.now()
#fill in missing gaps in images by copying the last image up
fill_in_gaps(folder, start_number)
#If test
testing = ""
if test:
testing = " -vframes " + str(300* int(x_speed)) + " "
not_verbose = ""
if not verbose:
not_verbose = "-nostats -loglevel 0"
if crop == "default":
crop = "scale=2800:-1, crop=1920:1080:352:740"
x_speed = "fps=30, setpts=(1/" + str(x_speed) + ")*PTS"
filter_v = "-filter:v \"" + x_speed +", " + crop + "\""
linux_command = "cd " + folder + "; /cygdrive/c/ffmpeg/bin/ffmpeg -err_detect ignore_err -y " + not_verbose + " -start_number " + str(start_number) + " -i G%07d.JPG " + testing + " " + filter_v + " -vcodec libx264 -pix_fmt yuv420p " + img_folder.replace("/cygdrive/c","C:") + "/" + video_name
if test:
print(linux_command)
os.system(linux_command)
if test:
os.system("open " + img_folder.replace("/cygdrive/c","C:") + "/" + video_name)
print_elapsed_time(individual_start_time, datetime.datetime.now())
else:
print("Folder does not exist '" + str(img_folder) + "' ... exiting")
sys.exit(1)
print(" === Job Complete == ")
print_elapsed_time(start_time, datetime.datetime.now())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment