Creation of Animated Images

To create animated images, we’ll first need to import the imageio library by running import imageio before we can use its functions.

From Individual Images

Create a folder in your current directory called source_images . Place the images that will contribute to the animated image in the folder you just created. The imageio library supports various image formats, including the most common ones like JPEG and PNG. For the purpose of creating this tutorial, I simply dropped 10 PNG files in the folder. For learning purposes, you can grab some PNG files from your personal collection.

We’ll run the following code to read the images by using the imageio ’s imread() method which will create a numpy array for each image with its RGBA values read. All of these images will be saved to a list called image_list .

from pathlib import Path image_path = Path('source_images')

images = list(image_path.glob('*.png'))

image_list = []

for file_name in images:

image_list.append(imageio.imread(file_name))

After you’re done with reading your images, you can simply check if all images have been read as they’re supposed by running len(image_list) , which should match the number of PNG files in the folder.

Once we have the list of all the read images, we’ll simply create the animated image using the mimwrite() method as below. Isn’t it handy?

imageio.mimwrite('animated_from_images.gif', image_list)

You’ll find out that the GIF image has been successfully created in the current directory. Leave it there for now. We’ll come back to it later.

From a Video

It’s also common to create an animated image from a video. The imageio-ffmpeg library supports various video formats, including very common ones like MOV, AVI, MPEG, MP4, and WMV. For the purpose of creating this tutorial, I simply placed a MOV file in the current directory.

First, we can read the video file by using the mimread() method, which reads a series of images from the specified uri . You need to update the uri to the one that you actually have in your own folder.

video_read = imageio.mimread('video_to_gif.mov')

This method will create a list of numpy arrays, as we did for creating an animated image from individual images. Like before, we can check how many frames are contained in this video by calling len(video_read) . Then, we’ll create an animated image from the array list.

imageio.mimwrite('animated_from_video.gif', video_read)

A GIF image as named above will be created in the current directory. Don’t open it for now. We’ll check this image in the next section — optimization.

Optimization of Animated Images

The previous section showed you the two most common ways how you create animated images. By now, you have created two animated images by following each of the above instructions.

Review of the Current Status

Before we start touching base on the optimization piece, let’s review where we are now. Here’s a quick evaluation.

The GIF files are created with the right file extension. Good.

Both files can be opened, and the images are indeed animated. Good. Note: If your computer doesn’t have a desktop software to open animated images. You can open them with Firefox or Chrome web browser, both of which can view animated images.

The speed in terms of fps (frames per second) doesn’t seem right, either too slow or too fast. Bad.

The file size of these two files seems to be larger than the ones that were downloaded before. Not So Good.

Apparently, these animated images are not too ready for us to use yet. For example, when the fps is too high, no one can really tell what it is. When the size is too large, the website may prevent you from uploading it or it will take too long to load the image, leading to negative user experience.

Let’s fix that by doing two simple things below.

Specify How the Animated Images Are Created

Recall that we used the mimwrite() method to create animated images. In addition to the target file and the list of image data, there are a few more parameters that can be set to further configure the creation of the GIF file. The complete list of supported parameters can be found in the official documentation.

Here, I’m highlighting the most frequently used parameters of the mimwrite() method.

loop: int. The number of iterations. The default value is 0 that means the animation will loop indefinitely. If you want to let the animation loop for a certain number of times, pass in that number.

The number of iterations. The default value is 0 that means the animation will loop indefinitely. If you want to let the animation loop for a certain number of times, pass in that number. fps: float. The number of frames per second. The default value is 10. This parameter basically determines how “fast” your animated image will look like.

The number of frames per second. The default value is 10. This parameter basically determines how “fast” your animated image will look like. duration : {float, list}. The duration of each frame in seconds. If one value is used, it will apply to all the frames. Alternatively, you can provide one value for each frame. If this parameter is not set, the default will be calculated as 1/fps.

In addition to these parameters for the mimwrite() method, when you create animated images, it’s also useful to specify additional parameters as listed below when you read the video using the mimread() method. The completed list of supported parameters can be found here.

fps: float. The number of frames per second to read the data. If not set (the default is None), the file’s own fps will be used. I personally will set a number (e.g., 5 or so to start with) for this parameter such that the number of frames will be reduced, so is the created animated image.

The number of frames per second to read the data. If not set (the default is None), the file’s own fps will be used. I personally will set a number (e.g., 5 or so to start with) for this parameter such that the number of frames will be reduced, so is the created animated image. loop: bool. A boolean value to indicate if the video needs to rewind when a frame is requested beyond the last one. The default is False. Usually, you don’t need to worry about this parameter, but sometimes, if you want your animated image to have repetitions of the frames from a video, you can set it as True.

A boolean value to indicate if the video needs to rewind when a frame is requested beyond the last one. The default is False. Usually, you don’t need to worry about this parameter, but sometimes, if you want your animated image to have repetitions of the frames from a video, you can set it as True. size: str | tuple. This parameter is a string tuple that specifies the frame size to read the images, such as (100, 100). You can leave out setting this parameter in most cases, as the data will be re-scaled automatically.

Please remember that oftentimes you need to experiment with these parameters to find out the ones that work best to the image you’re making.

Reduce File Size

We just learned how to tweak the reading and writing options to make the animated images better, but sometimes the file size is still bigger than ideal. Fortunately, there is a handy Python library pygifsicle that can get this job done with a few lines of code.

from pygifsicle import optimize gif_path = ' animated_from_video.gif' # create a new one

optimize(gif_path, 'animated_from_video_optimized.gif') # overwrite the original one

optimize(gif_path)