Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Programmatically generate video or animated GIF in Python?

I'd recommend not using images2gif from visvis because it has problems with PIL/Pillow and is not actively maintained (I should know, because I am the author).

Instead, please use imageio, which was developed to solve this problem and more, and is intended to stay.

Quick and dirty solution:

import imageio
images = []
for filename in filenames:
    images.append(imageio.imread(filename))
imageio.mimsave('/path/to/movie.gif', images)

For longer movies, use the streaming approach:

import imageio
with imageio.get_writer('/path/to/movie.gif', mode='I') as writer:
    for filename in filenames:
        image = imageio.imread(filename)
        writer.append_data(image)

Here's how you do it using only PIL (install with: pip install Pillow):

import glob
from PIL import Image

# filepaths
fp_in = "/path/to/image_*.png"
fp_out = "/path/to/image.gif"

# https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html#gif
img, *imgs = [Image.open(f) for f in sorted(glob.glob(fp_in))]
img.save(fp=fp_out, format='GIF', append_images=imgs,
         save_all=True, duration=200, loop=0)

See docs: https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html#gif


Well, now I'm using ImageMagick. I save my frames as PNG files and then invoke ImageMagick's convert.exe from Python to create an animated GIF. The nice thing about this approach is I can specify a frame duration for each frame individually. Unfortunately this depends on ImageMagick being installed on the machine. They have a Python wrapper but it looks pretty crappy and unsupported. Still open to other suggestions.


As of June 2009 the originally cited blog post has a method to create animated GIFs in the comments. Download the script images2gif.py (formerly images2gif.py, update courtesy of @geographika).

Then, to reverse the frames in a gif, for instance:

#!/usr/bin/env python

from PIL import Image, ImageSequence
import sys, os
filename = sys.argv[1]
im = Image.open(filename)
original_duration = im.info['duration']
frames = [frame.copy() for frame in ImageSequence.Iterator(im)]    
frames.reverse()

from images2gif import writeGif
writeGif("reverse_" + os.path.basename(filename), frames, duration=original_duration/1000.0, dither=0)

I used images2gif.py which was easy to use. It did seem to double the file size though..

26 110kb PNG files, I expected 26*110kb = 2860kb, but my_gif.GIF was 5.7mb

Also because the GIF was 8bit, the nice png's became a little fuzzy in the GIF

Here is the code I used:

__author__ = 'Robert'
from images2gif import writeGif
from PIL import Image
import os

file_names = sorted((fn for fn in os.listdir('.') if fn.endswith('.png')))
#['animationframa.png', 'animationframb.png', 'animationframc.png', ...] "

images = [Image.open(fn) for fn in file_names]

print writeGif.__doc__
# writeGif(filename, images, duration=0.1, loops=0, dither=1)
#    Write an animated gif from the specified images.
#    images should be a list of numpy arrays of PIL images.
#    Numpy images of type float should have pixels between 0 and 1.
#    Numpy images of other types are expected to have values between 0 and 255.


#images.extend(reversed(images)) #infinit loop will go backwards and forwards.

filename = "my_gif.GIF"
writeGif(filename, images, duration=0.2)
#54 frames written
#
#Process finished with exit code 0

Here are 3 of the 26 frames:

Here are 3 of the 26 frames

shrinking the images reduced the size:

size = (150,150)
for im in images:
    im.thumbnail(size, Image.ANTIALIAS)

smaller gif


To create a video, you could use opencv,

#load your frames
frames = ...
#create a video writer
writer = cvCreateVideoWriter(filename, -1, fps, frame_size, is_color=1)
#and write your frames in a loop if you want
cvWriteFrame(writer, frames[i])

I came across this post and none of the solutions worked, so here is my solution that does work

Problems with other solutions thus far:
1) No explicit solution as to how the duration is modified
2) No solution for the out of order directory iteration, which is essential for GIFs
3) No explanation of how to install imageio for python 3

install imageio like this: python3 -m pip install imageio

Note: you'll want to make sure your frames have some sort of index in the filename so they can be sorted, otherwise you'll have no way of knowing where the GIF starts or ends

import imageio
import os

path = '/Users/myusername/Desktop/Pics/' # on Mac: right click on a folder, hold down option, and click "copy as pathname"

image_folder = os.fsencode(path)

filenames = []

for file in os.listdir(image_folder):
    filename = os.fsdecode(file)
    if filename.endswith( ('.jpeg', '.png', '.gif') ):
        filenames.append(filename)

filenames.sort() # this iteration technique has no built in order, so sort the frames

images = list(map(lambda filename: imageio.imread(filename), filenames))

imageio.mimsave(os.path.join('movie.gif'), images, duration = 0.04) # modify duration as needed