23. Creating Videos from One or More Images
By Bernd Klein. Last modified: 04 Apr 2023.
This chapter of our Python course deals with films and images. You will learn how to create films out of images.
A Video from Multiple Pictures
So, you have a bunch of images and you would like to turn them into a vieo. In a way that each picture is shown for a certain amount of time. We assume that all your images, - which might be photographs you have taken in your last holiday or paintings you have made at same point in time - are in a directory. What we assume now is that all your paintings have the same size, if not you will also learn how to resize these images. For our purposes it might be good that the image names are following a special naming scheme, i.e. they all start with the same prefix (like 'pic_' e.g.) followed by a number (e.g. '001', '002', '003', ...) in an increasing order. The last part of the name is of course the suffix, which has to match the actual picture format.
You can download all the necessary images and the created videos for personal usage (copyright is by me) at python-courses: Material
First we provide a function 'seq_renaming' which will rename all the pictures in a folder according to the previously described naming scheme:
import glob
import os
def seq_renaming(folder='.', prefix='pic_', start=0, num_length=3):
count = start
folder += '/'
for fname in glob.glob(folder + '*.jpg'):
suffix = fname[fname.rfind('.'):]
outstr = f"{folder}/{prefix}{count:0{num_length}d}{suffix}"
count += 1
os.rename(fname, outstr)
seq_renaming('flower_images')
To test our newly created function and to demonstrate how it works, we create a test directory with empty files, simulating images:
import shutil
target_dir = 'test_dir'
if os.path.exists(target_dir):
# delete the existing directory
shutil.rmtree(target_dir)
# Create target_dir, because it doesn't exist so far
os.makedirs(target_dir)
names = ['apples', 'oranges', 'bananas', 'pears']
for name in names:
open(f'{target_dir}/{name}.jpg', 'w').write(' ')
print('Before renaming: ', os.listdir(target_dir))
# Let's rename the image names:
seq_renaming(target_dir)
print('After renaming: ', os.listdir(target_dir))
OUTPUT:
Before renaming: ['apples.jpg', 'oranges.jpg', 'bananas.jpg', 'pears.jpg'] After renaming: ['pic_000.jpg', 'pic_001.jpg', 'pic_002.jpg', 'pic_003.jpg']
Our first video will be created by using the images in the folder flower_images. Let's look at one of the images.
import matplotlib.pyplot as plt
import random
import numpy as np
import cv2
image = plt.imread("im2video/images/20210617_201910.jpg")
plt.imshow(image)
#cv2.imshow(image)
OUTPUT:
<matplotlib.image.AxesImage at 0x7f9793bbfbd0>
The picture is taken in Radolfzell part of Lake Constance and in the background you can see the mountains Hohentwiel and Hohenstoffeln.
import matplotlib.pyplot as plt
import random
import numpy as np
import os
import cv2
import glob
def get_frame_size(image_path):
""" Reads an image and calculates
the width and length of the images,
which will be returned """
frame = cv2.imread(image_path)
height, width, layers = frame.shape
frame_size = (width, height)
return frame_size
def video_from_images(folder='.',
video_name = 'video.avi',
suffix='png',
prefix='pic_',
reverse=False,
length_of_video_in_seconds=None,
codec = cv2.VideoWriter_fourcc(*'DIVX')):
""" The function creates a video from all the images with
the suffix (default is 'png' and the prefix (default is 'pic_'
in the folder 'folder'. If 'length_of_video_in_seconds' is set
to None, it will be the number of images in seconds. If a positive
value is given this will be the length of the video in seconds.
The function assumes that the the shape of the first image is
the one for all the images. If not a warning will be printed
and the size will be adapted accordingly! """
images = []
for fname in glob.glob(f'{folder}/{prefix}*{suffix}'):
images.append(fname)
images.sort(reverse=reverse)
if length_of_video_in_seconds is None:
# each image will be shown for one second
length_of_video_in_seconds = len(images)
# calculate number of frames per seconds:
frames_per_second = len(images) / length_of_video_in_seconds
frame_size = get_frame_size(images[0])
video = cv2.