我有一系列的图片,我想从中创建一个视频。理想情况下,我可以为每帧指定帧持续时间,但固定的帧速率也可以。我在wxPython中这样做,所以我可以渲染到wxDC或我可以将图像保存到文件,如PNG。是否有一个Python库,将允许我创建一个视频(AVI, MPG等)或一个动画GIF从这些帧?

编辑:我已经尝试过PIL,它似乎不起作用。有人能用这个结论来纠正我吗?这个链接似乎支持我关于PIL的结论:http://www.somethinkodd.com/oddthinking/2005/12/06/python-imaging-library-pil-and-animated-gifs/


当前回答

我使用images2gif.py,这很容易使用。它似乎是文件大小的两倍。

26个110kb的PNG文件,我期望26*110kb = 2860kb,但my_gif.GIF是5.7mb

另外,因为GIF是8位的,好看的png在GIF中变得有点模糊

下面是我使用的代码:

__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

以下是26帧中的3帧:

缩小图像会减小尺寸:

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

其他回答

就像沃伦去年说的,这是一个老问题。由于人们似乎仍然在浏览页面,我想将他们重定向到一个更现代的解决方案。就像blakev说的,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()

注意:这个例子已经过时了(gifmaker不是一个可导入的模块,只是一个脚本)。Pillow有一个GifImagePlugin(其源代码在GitHub上),但ImageSequence上的文档似乎表明有限的支持(只读)

你试过PyMedia吗?我不是100%确定,但看起来这个教程的例子针对的是你的问题。

它不是一个python库,但mencoder可以做到这一点:从多个输入图像文件编码。你可以像这样从python中执行mencoder:

import os

os.system("mencoder ...")

正如上面提到的一个成员,imageio是一种很好的方法。imageio还允许你设置帧速率,我实际上用Python写了一个函数,允许你设置最后一帧的暂停。我将此函数用于科学动画,其中循环是有用的,但立即重新启动不是。下面是链接和函数:

如何使用Python制作GIF

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)

我建议不要使用visvis的images2gif,因为它有PIL/Pillow的问题,并且没有积极维护(我应该知道,因为我是作者)。

相反,请使用imageio,它是为解决这个问题而开发的,并打算保留。

快速而肮脏的解决方案:

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

对于较长的电影,使用流媒体方法:

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)