Py学习  »  Python

在Python中将png文件转换为动画gif

Emad Boctor • 4 年前 • 2172 次点击  

编辑:我已经试过PIL了,但似乎没用。有人能用这个结论纠正我吗?或者建议另一个工具包?这个链接似乎支持我关于PIL的结论: http://www.somethinkodd.com/oddthinking/2005/12/06/python-imaging-library-pil-and-animated-gifs/

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/53872
 
2172 次点击  
文章 [ 21 ]  |  最新文章 4 年前
Apostolos
Reply   •   1 楼
Apostolos    6 年前

真是难以置信。。。所有人都提出了一些特殊的包来播放动画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()

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

Sam Perry
Reply   •   2 楼
Sam Perry    4 年前

我知道你问过要把图像转换成gif;但是,如果原始格式是MP4,你可以使用 FFmpeg

ffmpeg -i input.mp4 output.gif
willem
Reply   •   3 楼
willem    4 年前

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()
Apostolos
Reply   •   4 楼
Apostolos    5 年前

我碰到了皮尔的 图像序列 之后() 这次的方法,比 时间。睡眠() .

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()
Cro-Magnon
Reply   •   5 楼
Cro-Magnon    6 年前

我只是试了一下,非常有用:

首先下载库 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)
MedImage
Reply   •   6 楼
MedImage    6 年前

我在找一个 单行代码 我找到了下面的申请表。以下是我所做的:

第一步: 从下面的链接安装ImageMagick

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

enter image description here

将命令行指向放置图像(在我的示例中是.png格式)的文件夹

enter image description here

第三步:

magick -quality 100 *.png outvideo.mpeg

enter image description here

多谢雾鸟的建议!

ArKE
Reply   •   7 楼
ArKE    9 年前

该任务可以通过从与图片文件序列相同的文件夹运行两行python脚本来完成。对于png格式的文件,脚本是-

from scitools.std import movie
movie('*.png',fps=1,output_file='thisismygif.gif')
Pkjain
Reply   •   8 楼
Pkjain    6 年前

对我来说,最简单的事情就是用Python调用shell命令。

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。

Milap Jacek Słoma
Reply   •   9 楼
Milap Jacek Słoma    8 年前

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)
Jakub Å turc
Reply   •   10 楼
Jakub Å turc    14 年前

PyMedia ? 我不是百分之百确定,但看起来 this tutorial example 针对你的问题。

Engineer's Maker Portal
Reply   •   11 楼
Engineer's Maker Portal    5 年前

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

Example GIF using this method

Warren Weckesser
Reply   •   12 楼
Warren Weckesser    5 年前

老问题,很多好的答案,但可能还有兴趣在另一个选择。。。

这个 numpngw https://github.com/WarrenWeckesser/numpngw )可以从numpy数组中编写动画PNG文件。( 更新 新浪 现在在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)

创建:

animated png

您需要一个支持动画PNG的浏览器(直接或通过插件)来查看动画。

willurd
Reply   •   13 楼
willurd    15 年前

它不是python库,但mencoder可以做到: Encoding from multiple input image files . 您可以从python中执行mencoder,如下所示:

import os

os.system("mencoder ...")
Lucas Cimon Nathan
Reply   •   14 楼
Lucas Cimon Nathan    6 年前

就像沃伦说的 ,这是个老问题。由于人们似乎仍在浏览网页,我想把他们引向更现代的解决方案。就像布莱克夫说的 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 似乎表示支持有限(只读)

Daniel McGrath
Reply   •   15 楼
Daniel McGrath    5 年前

有效的解决方案

迄今为止其他解决办法的问题:
(一)
2个) 没有解决无序目录迭代的方法,这对于GIFs是必不可少的
三) 没有解释如何为python 3安装imageio

按如下方式安装imageio: python3-m pip安装imageio

注: 您需要确保您的帧在文件名中有某种索引,以便对它们进行排序,否则您将无法知道GIF的开始或结束位置

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
Kris
Reply   •   16 楼
Kris    4 年前

只有皮尔 (安装时使用: 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)

attwad
Reply   •   17 楼
attwad    14 年前

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])
robert king
Reply   •   18 楼
robert king    11 年前

我用过 images2gif.py

26个110kb的PNG文件,我希望26*110kb=2860kb,但是我的gif.gif是5.7mb

这是我使用的代码:

__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帧:

Here are 3 of the 26 frames

缩小图像缩小了大小:

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

smaller gif

Matt Bierner kostmo
Reply   •   19 楼
Matt Bierner kostmo    7 年前

截至2009年6月,最初引用的博客文章有一种方法来创建动画gif in the comments . 下载脚本 images2gif.py (以前 images2gif.py

然后,要反转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)
FogleBird
Reply   •   20 楼
FogleBird    15 年前