python-course.eu

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.