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

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


当前回答

真是不可思议……所有人都提出了一些特殊的包来播放动画GIF,目前它可以用Tkinter和经典的PIL模块!

这是我自己的GIF动画方法(我之前创建的)。非常简单:

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()

您可以设置自己的方法来停止动画。如果你想要完整版本的播放/暂停/退出按钮,请告诉我。

注意:我不确定连续帧是从内存还是从文件(磁盘)读取的。在第二种情况下,如果它们都一次读取并保存到一个数组(列表)中,那么效率会更高。(我没兴趣知道!:)

其他回答

我建议不要使用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)

现在我在用ImageMagick。我将帧保存为PNG文件,然后从Python中调用ImageMagick的convert.exe来创建一个动画GIF。这种方法的好处是我可以为每一帧单独指定帧持续时间。不幸的是,这取决于ImageMagick安装在机器上。他们有一个Python包装器,但它看起来很糟糕,不受支持。还在考虑其他建议。

我偶然发现了PIL的ImageSequence模块,它提供了更好(更标准)的GIF动画。这次我也使用了Tk的after()方法,这比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()

正如上面提到的一个成员,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)

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

import os

os.system("mencoder ...")