我有一系列想要制作视频的图片。理想情况下,我可以为每个帧指定帧持续时间,但固定的帧速率也可以。我在wxPython中这样做,所以我可以渲染到wxDC,或者我可以将图像保存到文件,如PNG。是否有Python库允许我从这些帧创建视频(AVI,MPG等)或动画GIF?
编辑:我已经尝试过PIL,但似乎无法正常工作。有人可以用这个结论纠正我或建议另一个工具包吗?此链接似乎支持我关于PIL的结论:http://www.somethinkodd.com/oddthinking/2005/12/06/python-imaging-library-pil-and-animated-gifs/
答案 0 :(得分:188)
我建议不要使用来自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)
答案 1 :(得分:41)
截至2009年6月,最初引用的博客文章有一种创建动画GIF in the comments的方法。下载脚本images2gif.py(以前为images2gif.py,更新@geographika提供)。
然后,要反转gif中的帧,例如:
#!/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)
答案 2 :(得分:38)
好吧,现在我正在使用ImageMagick。我将帧保存为PNG文件,然后从Python调用ImageMagick的convert.exe来创建动画GIF。这种方法的好处是我可以单独为每个帧指定帧持续时间。不幸的是,这取决于ImageMagick安装在机器上。他们有一个Python包装器,但它看起来很糟糕且不受支持。仍然接受其他建议。
答案 3 :(得分:25)
我使用了易于使用的images2gif.py。它似乎确实加倍了文件大小..
26个110kb PNG文件,我预计26 * 110kb = 2860kb,但my_gif.GIF是5.7mb
另外因为GIF是8bit,GIF中的png变得有点模糊
以下是我使用的代码:
__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)
答案 4 :(得分:18)
要制作视频,您可以使用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])
答案 5 :(得分:13)
这是使用仅PIL (安装: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)
答案 6 :(得分:5)
它不是python库,但是mencoder可以做到:Encoding from multiple input image files。您可以像这样从python执行mencoder:
import os
os.system("mencoder ...")
答案 7 :(得分:5)
就像沃伦去年所说的那样,这是一个老问题。由于人们似乎仍在查看页面,我想将它们重定向到更现代的解决方案。就像blakev所说的here一样,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
不是可导入模块,只是脚本)。枕头有GifImagePlugin(来源为on GitHub),但the doc on ImageSequence似乎表示支持有限(只读)
答案 8 :(得分:5)
我碰到了这篇文章,但没有一个解决方案起作用,所以这是我的有效解决方案
到目前为止,其他解决方案存在的问题:
1)对于持续时间的修改方式没有明确的解决办法
2)对于乱序目录迭代没有解决方案,这对于GIF是必不可少的
3)没有说明如何为python 3安装imageio
像这样安装imageio: python3 -m pip安装imageio
注意:您将要确保帧在文件名中具有某种索引,以便可以对其进行排序,否则,您将无法知道GIF的开始或结束位置
s_tweets.head()
print(s_tweets.iloc[:,2])
tweets = s_tweets.iloc[:,2]
#step 2: remove the special characters and punctuation
tlist = []
for t in tweets:
t_new=re.sub('[^A-Za-z0-9]+', ' ', t)
tlist.append(t_new)
#print(t_new)
#print(t_list)
test=word_tokenize(tlist[1])
print(test)
fname = 'tokensALL.json'
ff = open(fname, 'a')
for i in range(0,1751):
ff.write(str(word_tokenize(tlist[i])) + "\n")
ff.close()
###### find most frequent words
fname2 = 'tokensALL.json'
with open(fname2, 'r') as f:
count_all = Counter()
for line in f:
tweet = json.loads(line)
# Create a list with all the terms
terms_stop = [term for term in preprocess(tweet['text']) if
term not in stop]
# Update the counter
# terms_single = set(terms_all)
# Count hashtags only
terms_hash = [term for term in preprocess(tweet['text'])
if term.startswith('#')]
# Count terms only (no hashtags, no mentions)
terms_only = [term for term in preprocess(tweet['text'])
if term not in stop and
not term.startswith(('#', '@'))]
# mind the ((double brackets))
# startswith() takes a tuple (not a list) if
# we pass a list of inputs
terms_single = set(terms_stop)
terms_bigram = bigrams(terms_stop)
count_all.update(terms_stop)
# Print the first 5 most frequent words
print(count_all.most_common(5))
答案 9 :(得分:4)
你试过PyMedia吗?我不是100%确定,但看起来this tutorial example针对您的问题。
答案 10 :(得分:4)
老问题,很多好的答案,但可能仍然有兴趣另一种选择......
我最近在github上设置的numpngw
模块(https://github.com/WarrenWeckesser/numpngw)可以从numpy数组中编写动画PNG文件。 (更新:numpngw
现在位于pypi:https://pypi.python.org/pypi/numpngw。)
例如,这个脚本:
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)
创建:
您需要一个支持动画PNG的浏览器(直接或使用插件)来查看动画。
答案 11 :(得分:4)
使用windows7,python2.7,opencv 3.0,以下内容适用于我:
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)
答案 12 :(得分:4)
作为上述成员,imageio是实现此目的的好方法。 imageio还允许您设置帧速率,实际上我在Python中编写了一个函数,该函数允许您设置最终帧的保持时间。我将此功能用于科学动画,在这种动画中循环很有用,但没有立即重启。这是链接和功能:
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)
答案 13 :(得分:3)
我要发布一个答案,因为它比到目前为止发布的所有内容都更简单:
from PIL import Image
width = 300
height = 300
im1 = Image.new("RGBA", (width, height), (255, 0, 0))
im2 = Image.new("RGBA", (width, height), (255, 255, 0))
im3 = Image.new("RGBA", (width, height), (255, 255, 255))
im1.save("out.gif", save_all=True, append_images=[im2, im3], duration=100, loop=0)
使用现有图像:
from PIL import Image
im1 = Image.open('a.png')
im2 = Image.open('b.png')
im3 = Image.open('c.png')
im1.save("out.gif", save_all=True, append_images=[im2, im3], duration=100, loop=0)
而且,由于枕头的版本太低而无声地失败了,这是带有库版本检查的奖励版本:
from packaging import version
from PIL import Image
im1 = Image.open('a.png')
im2 = Image.open('b.png')
im3 = Image.open('c.png')
if version.parse(Image.PILLOW_VERSION) < version.parse("3.4"):
print("Pillow in version not supporting making animated gifs")
print("you need to upgrade library version")
print("see release notes in")
print("https://pillow.readthedocs.io/en/latest/releasenotes/3.4.0.html#append-images-to-gif")
else:
im1.save("out.gif", save_all=True, append_images=[
im2, im3], duration=100, loop=0)
答案 14 :(得分:2)
使它适用于我的最简单的事情是在Python中调用shell命令。
如果存储的图像如dummy_image_1.png,dummy_image_2.png ... dummy_image_N.png,则可以使用以下功能:
import subprocess
def grid2gif(image_str, output_gif):
str1 = 'convert -delay 100 -loop 1 ' + image_str + ' ' + output_gif
subprocess.call(str1, shell=True)
执行:
grid2gif("dummy_image*.png", "my_output.gif")
这将构建你的gif文件my_output.gif。
答案 15 :(得分:2)
可以通过从与图片文件序列相同的文件夹中运行两行python脚本来完成任务。对于png格式化文件,脚本为 -
from scitools.std import movie
movie('*.png',fps=1,output_file='thisismygif.gif')
答案 16 :(得分:1)
我正在寻找单行代码,并发现以下内容适用于我的应用程序。这是我做的:
第一步: 从下面的链接安装ImageMagick
https://www.imagemagick.org/script/download.php
第二步: 将cmd行指向放置图像的文件夹(在我的情况下为.png格式)
第三步: 输入以下命令
magick -quality 100 *.png outvideo.mpeg
感谢FogleBird的想法!
答案 17 :(得分:1)
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)
标识不同文件名的索引的开始和结束值+1
imgs = glob.glob("*.png") #do this if you want to read all files ending with .png
我的文件是:snap596.png,snap597.png ...... snap690.png
frames = []
for i in imgs:
new_frame = Image.open(i)
frames.append(new_frame)
保存到永远循环的GIF文件中
frames[0].save('fire3_PIL.gif', format='GIF',
append_images=frames[1:],
save_all=True,
duration=300, loop=0)
我发现imageio出现了闪烁问题,并且此方法解决了该问题。
答案 18 :(得分:0)
我遇到了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()
答案 19 :(得分:0)
我只是尝试了以下内容并且非常有用:
首先将库Figtodat
和images2gif
下载到您的本地目录。
其次收集数组中的数字并将它们转换为动画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)
答案 20 :(得分:0)
制作GIF的简单函数:
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()
答案 21 :(得分:0)
我了解您问过有关将图像转换为gif的问题;但是,如果原始格式为MP4,则可以使用FFmpeg:
ffmpeg -i input.mp4 output.gif
答案 22 :(得分:0)
安装
pip install imageio-ffmpeg
pip install imageio
代码
import imageio
images = []
for filename in filenames:
images.append(imageio.imread(filename))
imageio.mimsave('movie.mp4', images)
保存为gif而不是gif时,可以提高质量并将大小从8Mb减小到80Kb
答案 23 :(得分:-1)
真的令人难以置信......所有人都提出了一些特殊的包装来播放动画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()
您可以设置自己的方法来停止动画。如果您想通过播放/暂停/退出按钮获取完整版本,请告诉我。
注意:我不确定是从内存还是从文件(磁盘)读取连续帧。在第二种情况下,如果它们全部读取并保存到数组(列表)中会更有效。 (我没有兴趣找到它!:)