Creating Videos with the Python Programming Language - DCGAN Time Lapse

Mathias Pfeil

Author

General Programming

Category

June 28 2019

Time Created

In my previous article, I showed some of the watches my DCGAN had generated. I thought it might be fun to create a time lapse of the training process, so I create a short script to do just that.

I will explain how this works in the article, but will also include a commented version at the bottom if you just want to copy and paste.


The script

First we need to import our dependencies, and set some basic variables.


import cv2
import moviepy.editor as mp
import datetime
import os

imgs = []

# Path to directory where images are stored
path = os.path.join('./','image_sets/images')

The path variable is the location of where our images for the video are stored and the "imgs" list is where we will keep those images.

Next, we want to make sure that our files are properly ordered once they are turned into a list. os.listdir does not always sort images the same way as they appear in a directory. The images we are grabbing are arranged by the epoch they were saved on, like this: '0.jpg', '1.jpg', '2.jpg'. Unfortunatly, once in a list they might show up like this: '2.jpg', '0.jpg', '1.jpg'.

In order to make sure they keep the same arrangement as in the directory, we will remove the file extension, demonstrated below. This gives us the following list: '2','0','1'


no_ext = [os.path.splitext(x)[0] for x in os.listdir(path)]

We can now sort images by the epoch they were saved on, which results in this: '0', '1', '2'


sorted_dir = sorted(no_ext, key=lambda x: int(x))

Add the file extension back and we are good to go.


sorted_dir = [x+'.jpg' for x in sorted_dir]

Now we will loop through list of images and append them to our imgs variable we defined earlier. You can think of these images as your frames.


for watch_img in sorted_dir:
    imgs.append(imread(os.path.join(path, watch_img)))

Now we will create the video. I want ten images per second, because this is a time lapse. I can do this by setting my frame rate to 30 in the line below, then giving each image only three frames in the for loop.


writer = cv2.VideoWriter("./output.mp4", cv2.VideoWriter_fourcc(*"MP4V"), 30,(640,480))

for frame in imgs:
    for i in range(3):
        writer.write(frame)
writer.release()

I want some music to play over my time lapse, so lets do that now.


save_time = datetime.datetime.now().strftime('%Y-%m-%d-%H-%M-%S')

videoclip = mp.VideoFileClip('./output.mp4')
audioclip = mp.AudioFileClip('./assets/music/st.mp3')
music = mp.afx.audio_loop( audioclip, duration=videoclip.duration)
video = videoclip.set_audio(music)
video.write_videofile(f"./timelapse-{save_time}.mp4")

videoclip.close()
audioclip.close()
music.close()
video.close()
os.remove(f"./output.mp4")

And that is it! We now have a short script that will create videos just using Python. While I am using this for a time lapse, this basic set up can be used to create more complex videos.

Here is the full code


import cv2
import moviepy.editor as mp
import datetime
import os

imgs = []

# Path to directory where images are stored
path = os.path.join('./','image_sets/images')

# os.listdir does not always sort images the same way as they appear in a directory.
# The images we are grabbing are arranged by the epoch they were saved on,
# like this: '0.jpg', '1.jpg', '2.jpg'. Unfortunately, once in a list they might
# show up like this: '2.jpg', '0.jpg', '1.jpg'
#
# In order to make sure they keep the same arrangement as in the directory, we will 
# remove the file extension, demonstrated below. This gives us the following list: '2','0','1'
no_ext = [os.path.splitext(x)[0] for x in os.listdir(path)]

# We can now sort images by the epoch they were saved on, which results in this: '0', '1', '2'
sorted_dir = sorted(no_ext, key=lambda x: int(x))

# Now we just add the file extension back and we are good to go.
sorted_dir = [x+'.jpg' for x in sorted_dir]

# Loop through list of images and append them to our images list.
for watch_img in sorted_dir:
    imgs.append(imread(os.path.join(path, watch_img)))
    
# Now we will create the video. I want ten images per second, because this is a time lapse.
# I can do this by setting my frame rate to 30 in the line below, then giving each image
# only three frames in the for loop.
writer = cv2.VideoWriter("./output.mp4", cv2.VideoWriter_fourcc(*"MP4V"), 30,(640,480))

for frame in imgs:
    for i in range(3):
        writer.write(frame)
writer.release()

# Add music to video
save_time = datetime.datetime.now().strftime('%Y-%m-%d-%H-%M-%S')

videoclip = mp.VideoFileClip('./output.mp4')
audioclip = mp.AudioFileClip('./assets/music/st.mp3')
music = mp.afx.audio_loop( audioclip, duration=videoclip.duration)
video = videoclip.set_audio(music)
video.write_videofile(f"./timelapse-{save_time}.mp4")

videoclip.close()
audioclip.close()
music.close()
video.close()
os.remove(f"./output.mp4")