345

I have a series of images that I want to create a video from. Ideally I could specify a frame duration for each frame but a fixed frame rate would be fine too. I'm doing this in wxPython, so I can render to a wxDC or I can save the images to files, like PNG. Is there a Python library that will allow me to create either a video (AVI, MPG, etc) or an animated GIF from these frames?

Edit: I've already tried PIL and it doesn't seem to work. Can someone correct me with this conclusion or suggest another toolkit? This link seems to backup my conclusion regarding PIL: http://www.somethinkodd.com/oddthinking/2005/12/06/python-imaging-library-pil-and-animated-gifs/

FogleBird
  • 74,300
  • 25
  • 125
  • 131

24 Answers24

441

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)
Matt Bierner
  • 58,117
  • 21
  • 175
  • 206
Almar
  • 4,756
  • 2
  • 13
  • 9
  • 76
    also parameter duration=0.5 sets the 0.5sec durations for each frame. – Alleo Sep 16 '16 at 18:30
  • 3
    ValueError: Could not find a format to read the specified file in mode 'i' - I'm getting this error on windows 2.7 winpython. Any clues? – DataScientYst Oct 04 '16 at 12:20
  • @Vanko what's the filename? Maybe open an issue on the imageio github page to discuss this. – Almar Oct 05 '16 at 20:55
  • Hi Almar the problem is with the output file: mpvoe.gif. It could be a problem related to my python configuration. I'm a newbie in python. What I did: 1) create a python module in eclipse(python 2,7 winpython) 2) pip install of imageio for winpython 3) run your code(with little modification for the folders). After several attempts I ended with this solution for gif generation: https://github.com/OmarIbannez/image2gif_example . I check the problems at the github page and I conclude that problem is due to configuration issue. – DataScientYst Oct 06 '16 at 05:46
  • 1
    @Vanko the error seems to be related to the reading of the file, you could try imagio.mimread, or if its a movie with many frames, use the reader object like here: http://imageio.readthedocs.io/en/latest/examples.html#iterate-over-frames-in-a-movie – Almar Oct 08 '16 at 19:57
  • 4
    @Alleo: "also parameter duration=0.5 sets the 0.5sec durations for each frame". There is a duration feature for imageio? If so, where is this documented? I read all the docs and couldn't find any mention of a duration argument. – Chris Nielsen Sep 28 '17 at 17:51
  • Here is a simple one liner to save an array `images` full of PIL images to a gif using imageio: `saveGifPIL = lambda filename, images, **mimsaveParams: imageio.mimsave(filename, [[(img.save(buf,format='png'), buf.seek(0), imageio.imread(buf))[2] for buf in [BytesIO()]][0] for img in images], **mimsaveParams)` then you can just do `saveGifPIL("blah.gif", images)` and also you can add arguments like `saveGifPIL("blah.gif", images, fps=20)` – Phylliida Dec 21 '17 at 21:50
  • 1
    1. Parameter `duration` can be passed as keyword arg to both `mimsave` and `get_writer`. 2. Nice library, it's a pity it doesn't do APNG. 3. Careful, `imageio` uses RGB arrays and OpenCV, by default, GBR. – Tomasz Gandor Jul 12 '18 at 08:02
  • 6
    Note that `imageio` does not work with images with transparency layer. Had to learn that the hard way... – xjcl Jan 14 '20 at 11:06
  • 9
    @ChrisNielsen, the 'duration = 0.5' goes into line 2. imageio.get_writer('/path/to/movie.gif', mode='I', **duration = 0.5**) as writer: – Cristina Jan 30 '20 at 09:25
  • @ChrisNielsen the duration arg is specific to GIF file formats, and is in the docs for imageio; https://imageio.readthedocs.io/en/stable/format_gif-pil.html#gif-pil – HaplessEcologist Dec 17 '20 at 21:44
  • wow, now I have several months using imageio and I remember that I met it because of this answer. – Moisés Briseño Estrello Jul 27 '22 at 09:01
177

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

import glob
import contextlib
from PIL import Image

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

# use exit stack to automatically close opened images
with contextlib.ExitStack() as stack:

    # lazily load images
    imgs = (stack.enter_context(Image.open(f))
            for f in sorted(glob.glob(fp_in)))

    # extract  first image from iterator
    img = next(imgs)

    # https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html#gif
    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

Kris
  • 22,079
  • 3
  • 30
  • 35
  • 1
    What does the asterisk variable holds ("*imgs")? – denisb411 Mar 31 '20 at 21:44
  • 9
    That's a python language feature. It does *iterable unpacking*. You can roughly think of it as unpacking `x = [a, b, c]` to `*x` which can be thought of as `a, b, c` (without the enclosing brackets). In function calls these are synonymous: `f(*x) == f(a, b, c)`. In tuple unpacking it's particularly useful in cases where you want to split an iterable into a head (first element) and a tail (the rest), which is what I do in this example. – Kris Apr 01 '20 at 01:43
  • 2
    This will load all images into memory at the same time which can easily exhaust it. – Smiley1000 Jan 30 '22 at 22:22
  • You're right, I'll edit it to use iterators instead. Note that PIL is clever enough not to load all images in memory, cf. https://github.com/python-pillow/Pillow/blob/main/src/PIL/GifImagePlugin.py#L523 – Kris Feb 21 '22 at 12:22
  • I find this answer very useful, however, if you execute this in an interactive shell (ipython), the images remain open as long as the shell runs. Therefore a closing method is required: `for t in (Image.open(f) for f in sorted(glob.glob(fp_in))): t.close()` – TheDronist Nov 22 '22 at 14:53
  • You're right. I updated the example. I hope it's still readable for most people. – Kris Nov 23 '22 at 04:38
  • Thanks, worked perfectly for me, but had to import ExitStack like this: `from contextlib import ExitStack` – seizethedata Jan 20 '23 at 19:13
  • Technically worked, but I noticed since I used transparency, that each frame stays drawn on the screen and the next frame simply gets stacked on top. By the end of the gif, it looks like a bunch of images stacked on top of each other. Is there a way to specify that each frame gets destroyed after it is shown? – Logan Price May 30 '23 at 02:33
61

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.

FogleBird
  • 74,300
  • 25
  • 125
  • 131
  • 24
    I'm a Python guy but found ImageMagick much easier here. I just made my sequence of images and ran something like `convert -delay 20 -loop 0 *jpg animated.gif` – Nick Apr 03 '14 at 01:41
  • I agree, this is the best solution that I've come across. Here's a minimal example (based on the user Steve B's example code posted at http://stackoverflow.com/questions/10922285/is-there-a-simple-way-to-make-and-save-an-animation-with-pygame): http://pastebin.com/JJ6ZuXdz – andreasdr Nov 04 '14 at 19:42
  • Using ImageMagick, you can also easily resize the animated gif such as `convert -delay 20 -resize 300x200 -loop 0 *jpg animated.gif ` – Jun Wang Nov 29 '17 at 15:47
  • wont this run into issues in that it depends on using a `*.jpg` style list of input items, eventually running into CLI command length problems and also problems with consistent ordering of the items? – user5359531 Dec 21 '21 at 01:42
43

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)
Matt Bierner
  • 58,117
  • 21
  • 175
  • 206
kostmo
  • 6,222
  • 4
  • 40
  • 51
  • 2
    There is a new version of this script that makes much better quality output at http://visvis.googlecode.com/hg/vvmovie/images2gif.py it can be used as a standalone script separate from the package. – geographika May 09 '12 at 11:19
  • 1
    The script mentioned in this comment consistently gives a segmentation fault for me when used on Mac, even when simply run (using the __name__=='__main__' example). I'm trying the script mentioned in the answer, in hopes that it will work properly. EDIT - I can confirm that the script referenced in the answer above works correctly on my Mac. – scubbo May 22 '13 at 21:25
  • 6
    Rather than just download the script use pip e.g. `pip install visvis`, then in your script `from visvis.vvmovie.images2gif import writeGif`. – Daniel Farrell Jun 26 '13 at 00:56
  • 8
    I tried this with Python 2.7.3 on windows 8 and I get UnicodeDecodeError: 'ascii' codec can't decode byte 0xc8 in position 6: ordinal not in range(128). From running python images2gif.py – reckoner Jan 16 '14 at 21:49
  • Is there a way to run through the GIF only 1 time. I have tried loops=0 and loops=1, but no luck!? – dklassen Jun 02 '14 at 21:12
  • 3
    I am the author of visivis (and images2gif) and recommend against using it for this purpose. I've been working on a better solution as part of the imageio project (see my answer). – Almar Mar 11 '16 at 15:20
28

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

Rusty Rob
  • 16,489
  • 8
  • 100
  • 116
  • I made a blog post about this.. http://www.robert-king.com/#post2-python-makes-gif – Rusty Rob Apr 30 '12 at 04:30
  • 4
    @robertking with the code I got an error saying `fp.write(globalPalette) TypeError: must be string or buffer, not list` – LWZ Aug 20 '13 at 01:13
  • You may have a different version which takes a string rather than a list. Or perhaps you're passing a string instead of a list by mistake? – Rusty Rob Aug 20 '13 at 02:36
  • Image2Gif is no longer developed and not stable and therefore not recommend, use imageio instead! – Philipp Schwarz Jun 14 '16 at 08:58
  • I downloaded 'images2gif.py' and tried to run it (alone or using the code you are providing) and I got the following error on line 100 (`fp.write(palette)`): **TypeError: argument 1 must be string or buffer, not None**. This is because pallete is set from `getheader(im)[1]`, which is null (None). Is your code OK? – Apostolos Jun 13 '18 at 21:33
  • @Apostolos i'm not sure sorry ! – Rusty Rob Jun 13 '18 at 21:40
  • GIF uses a ancient compression technique "LZ77", which is inferior compared to the PNG's [zlib](https://www.zlib.net/). – tripulse Feb 17 '20 at 17:13
21

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])
attwad
  • 935
  • 8
  • 21
11

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
Daniel McGrath
  • 454
  • 5
  • 6
  • 1
    `sort` might yield unexpected results if your numbering scheme does not include leading zeros. Also why did you use map instead of a simple list comprehension? – NOhs Feb 07 '19 at 14:15
  • 1
    I'd suggest to do `filenames.append(os.path.join(path, filename))` – trueter Oct 28 '19 at 18:23
  • Secodning Nohs, `images = [imageio.imread(f) for f in filenames]` is cleaner, faster, and more pythonic. – Brandon Dube Nov 03 '19 at 17:10
7
from PIL import Image
import glob  #use it if you want to read all of the certain file type in the directory
imgs=[]
for i in range(596,691): 
    imgs.append("snap"+str(i)+'.png')
    print("scanned the image identified with",i)  

starting and ending value+1 of the index that identifies different file names

imgs = glob.glob("*.png") #do this if you want to read all files ending with .png

my files were: snap596.png, snap597.png ...... snap690.png

frames = []
for i in imgs:
    new_frame = Image.open(i)
    frames.append(new_frame)

Save into a GIF file that loops forever

frames[0].save('fire3_PIL.gif', format='GIF',
    append_images=frames[1:],
    save_all=True,
    duration=300, loop=0)

I found flickering issue with imageio and this method fixed it.

Binod
  • 397
  • 4
  • 5
6

Old question, lots of good answers, but there might still be interest in another alternative...

The numpngw module that I recently put up on github (https://github.com/WarrenWeckesser/numpngw) can write animated PNG files from numpy arrays. (Update: numpngw is now on pypi: https://pypi.python.org/pypi/numpngw.)

For example, this script:

import numpy as np
import numpngw


img0 = np.zeros((64, 64, 3), dtype=np.uint8)
img0[:32, :32, :] = 255
img1 = np.zeros((64, 64, 3), dtype=np.uint8)
img1[32:, :32, 0] = 255
img2 = np.zeros((64, 64, 3), dtype=np.uint8)
img2[32:, 32:, 1] = 255
img3 = np.zeros((64, 64, 3), dtype=np.uint8)
img3[:32, 32:, 2] = 255
seq = [img0, img1, img2, img3]
for img in seq:
    img[16:-16, 16:-16] = 127
    img[0, :] = 127
    img[-1, :] = 127
    img[:, 0] = 127
    img[:, -1] = 127

numpngw.write_apng('foo.png', seq, delay=250, use_palette=True)

creates:

animated png

You'll need a browser that supports animated PNG (either directly or with a plugin) to see the animation.

Warren Weckesser
  • 110,654
  • 19
  • 194
  • 214
6

Like Warren said last year, this is an old question. Since people still seem to be viewing the page, I'd like to redirect them to a more modern solution. Like blakev said here, there is a Pillow example on github.

 import ImageSequence
 import Image
 import gifmaker
 sequence = []

 im = Image.open(....)

 # im is your original image
 frames = [frame.copy() for frame in ImageSequence.Iterator(im)]

 # write GIF animation
 fp = open("out.gif", "wb")
 gifmaker.makedelta(fp, frames)
 fp.close()

Note: This example is outdated (gifmaker is not an importable module, only a script). Pillow has a GifImagePlugin (whose source is on GitHub), but the doc on ImageSequence seems to indicate limited support (reading only)

Lucas Cimon
  • 1,859
  • 2
  • 24
  • 33
Nathan
  • 145
  • 1
  • 5
6

As one member mentioned above, imageio is a great way to do this. imageio also allows you to set the frame rate, and I actually wrote a function in Python that allows you to set a hold on the final frame. I use this function for scientific animations where looping is useful but immediate restart isn't. Here is the link and the function:

How to make a GIF using Python

import matplotlib.pyplot as plt
import os
import imageio

def gif_maker(gif_name,png_dir,gif_indx,num_gifs,dpi=90):
    # make png path if it doesn't exist already
    if not os.path.exists(png_dir):
        os.makedirs(png_dir)

    # save each .png for GIF
    # lower dpi gives a smaller, grainier GIF; higher dpi gives larger, clearer GIF
    plt.savefig(png_dir+'frame_'+str(gif_indx)+'_.png',dpi=dpi)
    plt.close('all') # comment this out if you're just updating the x,y data

    if gif_indx==num_gifs-1:
        # sort the .png files based on index used above
        images,image_file_names = [],[]
        for file_name in os.listdir(png_dir):
            if file_name.endswith('.png'):
                image_file_names.append(file_name)       
        sorted_files = sorted(image_file_names, key=lambda y: int(y.split('_')[1]))

        # define some GIF parameters

        frame_length = 0.5 # seconds between frames
        end_pause = 4 # seconds to stay on last frame
        # loop through files, join them to image array, and write to GIF called 'wind_turbine_dist.gif'
        for ii in range(0,len(sorted_files)):       
            file_path = os.path.join(png_dir, sorted_files[ii])
            if ii==len(sorted_files)-1:
                for jj in range(0,int(end_pause/frame_length)):
                    images.append(imageio.imread(file_path))
            else:
                images.append(imageio.imread(file_path))
        # the duration is the time spent on each image (1/duration is frame rate)
        imageio.mimsave(gif_name, images,'GIF',duration=frame_length)

Example GIF using this method

Maker Portal
  • 61
  • 1
  • 3
6

Installation

pip install imageio-ffmpeg
pip install imageio

Code

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

Quality is raised and size is reduced from 8Mb to 80Kb when saving as mp4 than gif

Smart Manoj
  • 5,230
  • 4
  • 34
  • 59
5

It's not a python library, but mencoder can do that: Encoding from multiple input image files. You can execute mencoder from python like this:

import os

os.system("mencoder ...")
willurd
  • 11,745
  • 5
  • 28
  • 23
4

With windows7, python2.7, opencv 3.0, the following works for me:

import cv2
import os

vvw           =   cv2.VideoWriter('mymovie.avi',cv2.VideoWriter_fourcc('X','V','I','D'),24,(640,480))
frameslist    =   os.listdir('.\\frames')
howmanyframes =   len(frameslist)
print('Frames count: '+str(howmanyframes)) #just for debugging

for i in range(0,howmanyframes):
    print(i)
    theframe = cv2.imread('.\\frames\\'+frameslist[i])
    vvw.write(theframe)
Milap
  • 6,915
  • 8
  • 26
  • 46
Jacek Słoma
  • 91
  • 1
  • 6
4

The easiest thing that makes it work for me is calling a shell command in Python.

If your images are stored such as dummy_image_1.png, dummy_image_2.png ... dummy_image_N.png, then you can use the function:

import subprocess
def grid2gif(image_str, output_gif):
    str1 = 'convert -delay 100 -loop 1 ' + image_str  + ' ' + output_gif
    subprocess.call(str1, shell=True)

Just execute:

grid2gif("dummy_image*.png", "my_output.gif")

This will construct your gif file my_output.gif.

Pkjain
  • 41
  • 2
4

Have you tried PyMedia? I am not 100% sure but it looks like this tutorial example targets your problem.

Jakub Šturc
  • 35,201
  • 25
  • 90
  • 110
2

The task can be completed by running the two line python script from the same folder as the sequence of picture files. For png formatted files the script is -

from scitools.std import movie
movie('*.png',fps=1,output_file='thisismygif.gif')
ArKE
  • 74
  • 6
  • 1
    Tried it... didn't work for me under Python 2.6. Returned: "scitools.easyviz.movie function runs the command: / convert -delay 100 g4testC_*.png g4testC.gif / Invalid Parameter - 100" – Dan H Aug 13 '15 at 19:31
  • Problem is not with Python for sure. Reinstall imagemagick on your system and retry. – ArKE Oct 14 '15 at 09:19
  • This library seems to be dead. – shuhalo Feb 26 '23 at 18:26
2

Addition to Smart Manoj answers: Make a .mp4 movie from all images in a folder

Installation:

pip install imageio-ffmpeg
pip install imageio

Code:

import os
import imageio

root = r'path_to_folder_with_images'

images = []    
for subdir, dirs, files in os.walk(root):
    for file in files:
        images.append(imageio.imread(os.path.join(root,file)))

savepath = r'path_to_save_folder'
imageio.mimsave(os.path.join(savepath,'movie.mp4'), images)

PS: Make sure your "files" list is sorted the way you want, you will save some time if you already save your images accordingly

Butters
  • 53
  • 5
1

I was looking for a single line code and found the following to work for my application. Here is what I did:

First Step: Install ImageMagick from the link below

https://www.imagemagick.org/script/download.php

enter image description here

Second Step: Point the cmd line to the folder where the images (in my case .png format) are placed

enter image description here

Third Step: Type the following command

magick -quality 100 *.png outvideo.mpeg

enter image description here

Thanks FogleBird for the idea!

Adam Merckx
  • 1,122
  • 1
  • 14
  • 31
1

A simple function that makes GIFs:

import imageio
import pathlib
from datetime import datetime


def make_gif(image_directory: pathlib.Path, frames_per_second: float, **kwargs):
    """
    Makes a .gif which shows many images at a given frame rate.
    All images should be in order (don't know how this works) in the image directory

    Only tested with .png images but may work with others.

    :param image_directory:
    :type image_directory: pathlib.Path
    :param frames_per_second:
    :type frames_per_second: float
    :param kwargs: image_type='png' or other
    :return: nothing
    """
    assert isinstance(image_directory, pathlib.Path), "input must be a pathlib object"
    image_type = kwargs.get('type', 'png')

    timestampStr = datetime.now().strftime("%y%m%d_%H%M%S")
    gif_dir = image_directory.joinpath(timestampStr + "_GIF.gif")

    print('Started making GIF')
    print('Please wait... ')

    images = []
    for file_name in image_directory.glob('*.' + image_type):
        images.append(imageio.imread(image_directory.joinpath(file_name)))
    imageio.mimsave(gif_dir.as_posix(), images, fps=frames_per_second)

    print('Finished making GIF!')
    print('GIF can be found at: ' + gif_dir.as_posix())


def main():
    fps = 2
    png_dir = pathlib.Path('C:/temp/my_images')
    make_gif(png_dir, fps)

if __name__ == "__main__":
    main()
Willem
  • 11
  • 1
  • Thanks for providing this function. I figured that the ```sorted``` function may be added to your glob statement for ascending filenames so that images are in the right order. – hahnec Jan 10 '22 at 10:31
0

I just tried the following and was very useful:

First Download the libraries Figtodat and images2gif to your local directory.

Secondly Collect the figures in an array and convert them to an animated gif:

import sys
sys.path.insert(0,"/path/to/your/local/directory")
import Figtodat
from images2gif import writeGif
import matplotlib.pyplot as plt
import numpy

figure = plt.figure()
plot   = figure.add_subplot (111)

plot.hold(False)
    # draw a cardinal sine plot
images=[]
y = numpy.random.randn(100,5)
for i in range(y.shape[1]):
    plot.plot (numpy.sin(y[:,i]))  
    plot.set_ylim(-3.0,3)
    plot.text(90,-2.5,str(i))
    im = Figtodat.fig2img(figure)
    images.append(im)

writeGif("images.gif",images,duration=0.3,dither=0)
RRuiz
  • 2,159
  • 21
  • 32
0

I came upon PIL's ImageSequence module, which offers for a better (and more standard) GIF aninmation. I also use Tk's after() method this time, which is better than time.sleep().

from Tkinter import * 
from PIL import Image, ImageTk, ImageSequence

def stop(event):
  global play
  play = False
  exit() 

root = Tk()
root.bind("<Key>", stop) # Press any key to stop
GIFfile = {path_to_your_GIF_file}
im = Image.open(GIFfile); img = ImageTk.PhotoImage(im)
delay = im.info['duration'] # Delay used in the GIF file 
lbl = Label(image=img); lbl.pack() # Create a label where to display images
play = True;
while play:
  for frame in ImageSequence.Iterator(im):
    if not play: break 
    root.after(delay);
    img = ImageTk.PhotoImage(frame)
    lbl.config(image=img); root.update() # Show the new frame/image

root.mainloop()
Apostolos
  • 3,115
  • 25
  • 28
-1

It's really incredible ... All are proposing some special package for playing an animated GIF, at the moment that it can be done with Tkinter and the classic PIL module!

Here is my own GIF animation method (I created a while ago). Very simple:

from Tkinter import * 
from PIL import Image, ImageTk
from time import sleep

def stop(event):
  global play
  play = False
  exit() 

root = Tk()
root.bind("<Key>", stop) # Press any key to stop
GIFfile = {path_to_your_GIF_file}    
im = Image.open(GIFfile); img = ImageTk.PhotoImage(im)
delay = float(im.info['duration'])/1000; # Delay used in the GIF file 
lbl = Label(image=img); lbl.pack() # Create a label where to display images
play = True; frame = 0
while play:
  sleep(delay);
  frame += 1
  try:
    im.seek(frame); img = ImageTk.PhotoImage(im)
    lbl.config(image=img); root.update() # Show the new frame/image
  except EOFError:
    frame = 0 # Restart

root.mainloop()

You can set your own means to stop the animation. Let me know if you like to get the full version with play/pause/quit buttons.

Note: I am not sure if the consecutive frames are read from memory or from the file (disk). In the second case it would be more efficient if they all read at once and saved into an array (list). (I'm not so interested to find out! :)

Apostolos
  • 3,115
  • 25
  • 28
  • 1
    It's generally not a good ideal to call `sleep` in the main thread of a GUI. You can use the `after` method to call a function periodically. – Bryan Oakley Apr 16 '18 at 20:48
  • BTW, I normally use `tk.after()` myself. But here I needed to make the code as simple as possible. Whoever uses this GIF animation method can apply his own delay function. – Apostolos Apr 17 '18 at 17:28
-1

I understand you asked about converting images to a gif; however, if the original format is MP4, you could use FFmpeg:

ffmpeg -i input.mp4 output.gif
Sam Perry
  • 2,554
  • 3
  • 28
  • 29